vx-builder 0.0.2
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/.gitignore +17 -0
- data/.rspec +3 -0
- data/.travis.yml +15 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +40 -0
- data/lib/vx/builder/configuration.rb +20 -0
- data/lib/vx/builder/helper/config.rb +14 -0
- data/lib/vx/builder/helper/logger.rb +14 -0
- data/lib/vx/builder/helper/trace_sh_command.rb +16 -0
- data/lib/vx/builder/script/env.rb +21 -0
- data/lib/vx/builder/script/prepare.rb +59 -0
- data/lib/vx/builder/script/ruby.rb +59 -0
- data/lib/vx/builder/script/script.rb +22 -0
- data/lib/vx/builder/script/services.rb +25 -0
- data/lib/vx/builder/script/webdav_cache.rb +83 -0
- data/lib/vx/builder/script.rb +98 -0
- data/lib/vx/builder/source/constants.rb +11 -0
- data/lib/vx/builder/source/matrix.rb +113 -0
- data/lib/vx/builder/source/serializable.rb +43 -0
- data/lib/vx/builder/source.rb +106 -0
- data/lib/vx/builder/task.rb +27 -0
- data/lib/vx/builder/version.rb +5 -0
- data/lib/vx/builder.rb +38 -0
- data/spec/fixtures/travis.yml +5 -0
- data/spec/fixtures/travis_bug_1.yml +13 -0
- data/spec/fixtures/travis_bug_2.yml +18 -0
- data/spec/lib/builder/configuration_spec.rb +7 -0
- data/spec/lib/builder/script_spec.rb +29 -0
- data/spec/lib/builder/source_matrix_spec.rb +215 -0
- data/spec/lib/builder/source_spec.rb +183 -0
- data/spec/lib/builder/task_spec.rb +25 -0
- data/spec/lib/builder_spec.rb +17 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/create.rb +14 -0
- data/spec/support/fixture.rb +7 -0
- data/vx-builder.gemspec +29 -0
- metadata +192 -0
@@ -0,0 +1,113 @@
|
|
1
|
+
module Vx
|
2
|
+
module Builder
|
3
|
+
class Source
|
4
|
+
class Matrix
|
5
|
+
|
6
|
+
KEYS = (Source::LANGS + %w{ matrix_env:env }).freeze
|
7
|
+
NOT_MATRIX_KEYS = %w{ script before_script services }
|
8
|
+
|
9
|
+
attr_reader :source
|
10
|
+
|
11
|
+
def initialize(build_configuration)
|
12
|
+
@source = build_configuration
|
13
|
+
end
|
14
|
+
|
15
|
+
def keys
|
16
|
+
extract_pair_of_key_and_values.map(&:first).sort
|
17
|
+
end
|
18
|
+
|
19
|
+
def configurations
|
20
|
+
attributes_for_new_configurations_with_merged_env.map do |attrs|
|
21
|
+
attrs = attrs.merge(
|
22
|
+
NOT_MATRIX_KEYS.inject({}) do |a,v|
|
23
|
+
a[v] = source.public_send(v)
|
24
|
+
a
|
25
|
+
end
|
26
|
+
)
|
27
|
+
Source.new attrs
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def attributes_for_new_configurations_with_merged_env
|
32
|
+
attrs = attributes_for_new_configurations
|
33
|
+
attrs = [{}] if attrs.empty?
|
34
|
+
attrs.map do |a|
|
35
|
+
e = a["env"]
|
36
|
+
a["env"] = {
|
37
|
+
"global" => Array(e) + source.global_env,
|
38
|
+
"matrix" => e
|
39
|
+
}
|
40
|
+
a
|
41
|
+
end
|
42
|
+
attrs
|
43
|
+
end
|
44
|
+
|
45
|
+
def attributes_for_new_configurations
|
46
|
+
permutate_and_build_values.inject([]) do |ac, values|
|
47
|
+
ac << values.inject({}) do |a,val|
|
48
|
+
a[val.key] = val.value
|
49
|
+
a
|
50
|
+
end
|
51
|
+
ac
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def permutate_and_build_values
|
56
|
+
values = extract_pair_of_key_and_values.map do |key, vals|
|
57
|
+
vals.map{|it| Value.new(key, it) }
|
58
|
+
end
|
59
|
+
if matrix_values?(values)
|
60
|
+
array_permutations(values).map do |it|
|
61
|
+
if it.is_a?(Array)
|
62
|
+
it.flatten
|
63
|
+
else
|
64
|
+
[it]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
else
|
68
|
+
[values.flatten]
|
69
|
+
end.sort_by(&:to_s)
|
70
|
+
end
|
71
|
+
|
72
|
+
def extract_pair_of_key_and_values
|
73
|
+
KEYS.map.inject([]) do |a, k|
|
74
|
+
k_method, k_name = k.split(":")
|
75
|
+
k_name ||= k_method
|
76
|
+
|
77
|
+
if (val = source[k_method]) && !val.empty?
|
78
|
+
a << [k_name, val]
|
79
|
+
end
|
80
|
+
a
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def matrix_values?(values)
|
87
|
+
!values.all?{|i| i.size == 1 }
|
88
|
+
end
|
89
|
+
|
90
|
+
def array_permutations array, index=0
|
91
|
+
# index is 0 by default : start at the beginning, more elegant.
|
92
|
+
return array[-1] if index == array.size - 1 # Return last element if at end.
|
93
|
+
|
94
|
+
result = []
|
95
|
+
|
96
|
+
array[index].each do |element| # For each array
|
97
|
+
array_permutations(array, index + 1).each do |x| # Permute permute permute
|
98
|
+
result << [element, x]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
result
|
102
|
+
end
|
103
|
+
|
104
|
+
Value = Struct.new(:key, :value) do
|
105
|
+
def to_s
|
106
|
+
[key, value].join(":")
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Vx
|
5
|
+
module Builder
|
6
|
+
class Source
|
7
|
+
|
8
|
+
module Serializable
|
9
|
+
|
10
|
+
def self.included(base)
|
11
|
+
base.extend ClassMethods
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_yaml
|
15
|
+
YAML.dump(attributes)
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_hash
|
19
|
+
attributes
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
|
24
|
+
def from_file(file)
|
25
|
+
if File.readable? file
|
26
|
+
from_yaml File.read(file)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def from_yaml(yaml)
|
31
|
+
from_attributes YAML.load(yaml)
|
32
|
+
end
|
33
|
+
|
34
|
+
def from_attributes(attrs)
|
35
|
+
Source.new attrs
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require File.expand_path("../source/constants", __FILE__)
|
2
|
+
require File.expand_path("../source/matrix", __FILE__)
|
3
|
+
require File.expand_path("../source/serializable", __FILE__)
|
4
|
+
|
5
|
+
module Vx
|
6
|
+
module Builder
|
7
|
+
class Source
|
8
|
+
|
9
|
+
include Source::Serializable
|
10
|
+
|
11
|
+
attr_reader :attributes
|
12
|
+
alias_method :to_hash, :attributes
|
13
|
+
|
14
|
+
def initialize(attrs = {})
|
15
|
+
@attributes = normalize_attributes attrs
|
16
|
+
end
|
17
|
+
|
18
|
+
def [](val)
|
19
|
+
public_send(val)
|
20
|
+
end
|
21
|
+
|
22
|
+
def matrix_keys
|
23
|
+
@matrix_keys ||=
|
24
|
+
Matrix::KEYS.inject({}) do |a,k|
|
25
|
+
k_method, k_name = k.split(":")
|
26
|
+
k_name ||= k_method
|
27
|
+
val = send(k_method)
|
28
|
+
unless val.empty?
|
29
|
+
a[k_name] = val.first
|
30
|
+
end
|
31
|
+
a
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_matrix_s
|
36
|
+
@to_matrix_s ||= matrix_keys.map{|k,v| "#{k}:#{v}" }.sort.join(", ")
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_script_builder(build)
|
40
|
+
ScriptBuilder.new(build, self)
|
41
|
+
end
|
42
|
+
|
43
|
+
def env
|
44
|
+
attributes["env"]
|
45
|
+
end
|
46
|
+
|
47
|
+
def matrix_env
|
48
|
+
attributes["env"]["matrix"]
|
49
|
+
end
|
50
|
+
|
51
|
+
def global_env
|
52
|
+
attributes["env"]["global"]
|
53
|
+
end
|
54
|
+
|
55
|
+
AS_ARRAY.each do |m|
|
56
|
+
define_method m do
|
57
|
+
@attributes[m] || []
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def merge(attrs = {})
|
62
|
+
self.class.from_attributes self.attributes.merge(attrs)
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def normalize_attributes(attributes)
|
68
|
+
attributes = attributes.inject({}) do |a,row|
|
69
|
+
k,v = row
|
70
|
+
if AS_ARRAY.include?(k.to_s)
|
71
|
+
v = Array(v)
|
72
|
+
end
|
73
|
+
a[k.to_s] = v
|
74
|
+
a
|
75
|
+
end
|
76
|
+
normalize_env_attribute attributes
|
77
|
+
end
|
78
|
+
|
79
|
+
def normalize_env_attribute(attributes)
|
80
|
+
env = (attributes['env'] || {}) .dup
|
81
|
+
case env
|
82
|
+
when Hash
|
83
|
+
attributes["env"] = {
|
84
|
+
"matrix" => Array(env['matrix']),
|
85
|
+
"global" => Array(env['global'])
|
86
|
+
}
|
87
|
+
else
|
88
|
+
attributes['env'] = {
|
89
|
+
"matrix" => Array(env).map(&:to_s),
|
90
|
+
"global" => []
|
91
|
+
}
|
92
|
+
end
|
93
|
+
freeze_normalized_attributes attributes
|
94
|
+
end
|
95
|
+
|
96
|
+
def freeze_normalized_attributes(attributes)
|
97
|
+
attributes.freeze
|
98
|
+
attributes['env'].freeze
|
99
|
+
attributes['env']['global'].freeze
|
100
|
+
attributes['env']['matrix'].freeze
|
101
|
+
attributes
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Vx
|
2
|
+
module Builder
|
3
|
+
class Task
|
4
|
+
|
5
|
+
attr_reader :name, :src, :sha, :deploy_key, :branch, :pull_request_id
|
6
|
+
|
7
|
+
def initialize(name, src, sha, options = {})
|
8
|
+
@name = name
|
9
|
+
@src = src
|
10
|
+
@sha = sha
|
11
|
+
@deploy_key = options[:deploy_key]
|
12
|
+
@branch = options[:branch]
|
13
|
+
@pull_request_id = options[:pull_request_id]
|
14
|
+
|
15
|
+
validate!
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def validate!
|
21
|
+
(name && src && sha && deploy_key && branch) or
|
22
|
+
raise(MissingKeys)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/vx/builder.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.expand_path("../builder/version", __FILE__)
|
2
|
+
|
3
|
+
module Vx
|
4
|
+
module Builder
|
5
|
+
autoload :Source, File.expand_path("../builder/source", __FILE__)
|
6
|
+
autoload :Script, File.expand_path("../builder/script", __FILE__)
|
7
|
+
autoload :Task, File.expand_path("../builder/task", __FILE__)
|
8
|
+
autoload :Configuration, File.expand_path("../builder/configuration", __FILE__)
|
9
|
+
|
10
|
+
module Helper
|
11
|
+
autoload :Config, File.expand_path("../builder/helper/config", __FILE__)
|
12
|
+
autoload :Logger, File.expand_path("../builder/helper/logger", __FILE__)
|
13
|
+
autoload :TraceShCommand, File.expand_path("../builder/helper/trace_sh_command", __FILE__)
|
14
|
+
end
|
15
|
+
|
16
|
+
class MissingKeys < Exception ; end
|
17
|
+
|
18
|
+
extend self
|
19
|
+
|
20
|
+
def logger
|
21
|
+
config.logger
|
22
|
+
end
|
23
|
+
|
24
|
+
def configure
|
25
|
+
yield config if block_given?
|
26
|
+
config
|
27
|
+
end
|
28
|
+
|
29
|
+
def config
|
30
|
+
@config ||= Configuration.new
|
31
|
+
end
|
32
|
+
|
33
|
+
def reset_config!
|
34
|
+
@config = nil
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
rvm:
|
2
|
+
- "2.0.0"
|
3
|
+
|
4
|
+
env:
|
5
|
+
- DB=postgresql
|
6
|
+
|
7
|
+
before_script:
|
8
|
+
- cp config/samples/secret_token.rb config/initializers/secret_token.rb
|
9
|
+
- cp config/database.travis.yml config/database.yml
|
10
|
+
- bundle exec rake db:setup
|
11
|
+
|
12
|
+
script:
|
13
|
+
- bundle exec rake
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# bug: ignore services
|
2
|
+
rvm:
|
3
|
+
- "2.0.0"
|
4
|
+
|
5
|
+
services:
|
6
|
+
- elasticsearch
|
7
|
+
|
8
|
+
env:
|
9
|
+
- DB=postgresql
|
10
|
+
|
11
|
+
before_script:
|
12
|
+
- cp config/samples/secret_token.rb config/initializers/secret_token.rb
|
13
|
+
- cp config/database.travis.yml config/database.yml
|
14
|
+
- bundle exec rake db:setup
|
15
|
+
- bundle exec rake db:test:prepare
|
16
|
+
|
17
|
+
script:
|
18
|
+
- bundle exec rspec
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Vx::Builder::Script do
|
4
|
+
let(:task) { create :task }
|
5
|
+
let(:source) { create :source }
|
6
|
+
let(:script) { described_class.new task, source }
|
7
|
+
subject { script }
|
8
|
+
|
9
|
+
context "just created" do
|
10
|
+
its(:source) { should eq source }
|
11
|
+
its(:task) { should eq task }
|
12
|
+
end
|
13
|
+
|
14
|
+
context "#to_before_script" do
|
15
|
+
subject { script.to_before_script }
|
16
|
+
it { should be }
|
17
|
+
end
|
18
|
+
|
19
|
+
context "#to_after_script" do
|
20
|
+
subject { script.to_after_script }
|
21
|
+
it { should be }
|
22
|
+
end
|
23
|
+
|
24
|
+
context "#to_script" do
|
25
|
+
subject { script.to_script }
|
26
|
+
it { should be }
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,215 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
describe Vx::Builder::Source::Matrix do
|
5
|
+
let(:attributes) { {
|
6
|
+
env: %w{ FOO=1 BAR=2 },
|
7
|
+
rvm: %w{ 1.8.7 1.9.3 2.0.0 },
|
8
|
+
scala: %w{ 2.9.2 2.10.1 },
|
9
|
+
before_script: "echo before_script",
|
10
|
+
script: "echo script"
|
11
|
+
} }
|
12
|
+
let(:config) { Vx::Builder::Source.from_attributes attributes }
|
13
|
+
let(:matrix) { described_class.new config }
|
14
|
+
|
15
|
+
subject { matrix }
|
16
|
+
|
17
|
+
context "just created" do
|
18
|
+
its(:source) { should eq config }
|
19
|
+
end
|
20
|
+
|
21
|
+
context "keys" do
|
22
|
+
subject { matrix.keys }
|
23
|
+
it { should eq %w{ env rvm scala } }
|
24
|
+
context "without matrix" do
|
25
|
+
let(:attributes) { {} }
|
26
|
+
|
27
|
+
it { should eq [] }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'configurations' do
|
32
|
+
subject { matrix.configurations }
|
33
|
+
|
34
|
+
it "should copy script from source" do
|
35
|
+
expect(subject.map(&:script).uniq).to eq [["echo script"]]
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should copy before_script from source" do
|
39
|
+
expect(subject.map(&:before_script).uniq).to eq [["echo before_script"]]
|
40
|
+
end
|
41
|
+
|
42
|
+
context "without any matrix keys" do
|
43
|
+
let(:attributes) { {
|
44
|
+
script: %w{ /bin/true },
|
45
|
+
} }
|
46
|
+
|
47
|
+
it { should have(1).item }
|
48
|
+
its("first.attributes") { should eq(
|
49
|
+
"env" => {
|
50
|
+
"matrix" => [],
|
51
|
+
"global" => []
|
52
|
+
},
|
53
|
+
"script" =>["/bin/true"],
|
54
|
+
"before_script" =>[],
|
55
|
+
"services" => []
|
56
|
+
)}
|
57
|
+
end
|
58
|
+
|
59
|
+
context "with one env and one rvm key" do
|
60
|
+
let(:config) { Vx::Builder::Source.from_file fixture_path("travis_bug_1.yml") }
|
61
|
+
|
62
|
+
it{ should have(1).item }
|
63
|
+
|
64
|
+
context "attributes" do
|
65
|
+
subject { matrix.configurations.map(&:to_matrix_s) }
|
66
|
+
|
67
|
+
it { should eq ["env:DB=postgresql, rvm:2.0.0"] }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "with services key" do
|
72
|
+
let(:config) { Vx::Builder::Source.from_file fixture_path("travis_bug_2.yml") }
|
73
|
+
it { should have(1).item }
|
74
|
+
|
75
|
+
it "should have services" do
|
76
|
+
expect(matrix.configurations.first.services).to eq %w{ elasticsearch }
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
context "values" do
|
82
|
+
|
83
|
+
it { should have(12).items }
|
84
|
+
|
85
|
+
context "attributes" do
|
86
|
+
subject { matrix.configurations.map(&:to_matrix_s) }
|
87
|
+
|
88
|
+
it do
|
89
|
+
should eq [
|
90
|
+
"env:BAR=2, rvm:1.8.7, scala:2.10.1",
|
91
|
+
"env:FOO=1, rvm:1.8.7, scala:2.10.1",
|
92
|
+
"env:BAR=2, rvm:1.8.7, scala:2.9.2",
|
93
|
+
"env:FOO=1, rvm:1.8.7, scala:2.9.2",
|
94
|
+
"env:BAR=2, rvm:1.9.3, scala:2.10.1",
|
95
|
+
"env:FOO=1, rvm:1.9.3, scala:2.10.1",
|
96
|
+
"env:BAR=2, rvm:1.9.3, scala:2.9.2",
|
97
|
+
"env:FOO=1, rvm:1.9.3, scala:2.9.2",
|
98
|
+
"env:BAR=2, rvm:2.0.0, scala:2.10.1",
|
99
|
+
"env:FOO=1, rvm:2.0.0, scala:2.10.1",
|
100
|
+
"env:BAR=2, rvm:2.0.0, scala:2.9.2",
|
101
|
+
"env:FOO=1, rvm:2.0.0, scala:2.9.2"
|
102
|
+
]
|
103
|
+
end
|
104
|
+
|
105
|
+
context "without matrix" do
|
106
|
+
let(:attributes) { {
|
107
|
+
rvm: %w{ 2.0.0 },
|
108
|
+
} }
|
109
|
+
|
110
|
+
it { should eq ['rvm:2.0.0'] }
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context "attributes_for_new_confgurations_with_merged_env" do
|
118
|
+
subject { matrix.attributes_for_new_configurations_with_merged_env }
|
119
|
+
|
120
|
+
before do
|
121
|
+
attributes.merge!(
|
122
|
+
env: {
|
123
|
+
"global" => "FOO=1",
|
124
|
+
"matrix" => %w{ BAR=1 BAR=2 }
|
125
|
+
}
|
126
|
+
)
|
127
|
+
end
|
128
|
+
|
129
|
+
it { should have(12).items }
|
130
|
+
|
131
|
+
it "should merge matrix env to global env" do
|
132
|
+
expect(subject.map{|i| i["env"]["global"] }.uniq.sort).to eq([["BAR=1", "FOO=1"], ["BAR=2", "FOO=1"]])
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'attributes_for_new_configurations' do
|
137
|
+
subject { matrix.attributes_for_new_configurations }
|
138
|
+
|
139
|
+
it { should have(12).items }
|
140
|
+
|
141
|
+
its(:first) { should eq("rvm" => "1.8.7",
|
142
|
+
"scala" => "2.10.1",
|
143
|
+
"env" => "BAR=2") }
|
144
|
+
its(:last) { should eq("rvm" => "2.0.0",
|
145
|
+
"scala" => "2.9.2",
|
146
|
+
"env" => "FOO=1") }
|
147
|
+
end
|
148
|
+
|
149
|
+
context 'extract_pair_of_key_and_values' do
|
150
|
+
subject { matrix.extract_pair_of_key_and_values }
|
151
|
+
it {
|
152
|
+
should eq [
|
153
|
+
["rvm", %w{ 1.8.7 1.9.3 2.0.0 }],
|
154
|
+
["scala", %w{ 2.9.2 2.10.1 }],
|
155
|
+
["env", %w{ FOO=1 BAR=2 }]
|
156
|
+
]
|
157
|
+
}
|
158
|
+
end
|
159
|
+
|
160
|
+
context "permutate_and_build_values" do
|
161
|
+
subject { format_values matrix.permutate_and_build_values }
|
162
|
+
let(:expected) { [
|
163
|
+
%w{env:BAR=2 rvm:1.8.7 scala:2.10.1},
|
164
|
+
%w{env:BAR=2 rvm:1.8.7 scala:2.9.2},
|
165
|
+
%w{env:BAR=2 rvm:1.9.3 scala:2.10.1},
|
166
|
+
%w{env:BAR=2 rvm:1.9.3 scala:2.9.2},
|
167
|
+
%w{env:BAR=2 rvm:2.0.0 scala:2.10.1},
|
168
|
+
%w{env:BAR=2 rvm:2.0.0 scala:2.9.2},
|
169
|
+
%w{env:FOO=1 rvm:1.8.7 scala:2.10.1},
|
170
|
+
%w{env:FOO=1 rvm:1.8.7 scala:2.9.2},
|
171
|
+
%w{env:FOO=1 rvm:1.9.3 scala:2.10.1},
|
172
|
+
%w{env:FOO=1 rvm:1.9.3 scala:2.9.2},
|
173
|
+
%w{env:FOO=1 rvm:2.0.0 scala:2.10.1},
|
174
|
+
%w{env:FOO=1 rvm:2.0.0 scala:2.9.2},
|
175
|
+
] }
|
176
|
+
|
177
|
+
it { should eq expected }
|
178
|
+
|
179
|
+
context "with empty keys" do
|
180
|
+
let(:attributes) { {
|
181
|
+
env: %w{ FOO=1 BAR=2 },
|
182
|
+
rvm: %w{ 1.8.7 1.9.3 2.0.0 },
|
183
|
+
scala: %w{ 2.9.2 2.10.1 },
|
184
|
+
java: [],
|
185
|
+
go: nil
|
186
|
+
} }
|
187
|
+
it { should eq expected }
|
188
|
+
end
|
189
|
+
|
190
|
+
context "with one key" do
|
191
|
+
let(:attributes) { {
|
192
|
+
rvm: %w{ 1.9.3 2.0.0 },
|
193
|
+
} }
|
194
|
+
let(:expected) {[
|
195
|
+
%w{ rvm:1.9.3 },
|
196
|
+
%w{ rvm:2.0.0 }
|
197
|
+
]}
|
198
|
+
it { should eq expected }
|
199
|
+
end
|
200
|
+
|
201
|
+
context "without matrix" do
|
202
|
+
let(:attributes) { {
|
203
|
+
rvm: %w{ 2.0.0 },
|
204
|
+
} }
|
205
|
+
let(:expected) {[
|
206
|
+
%w{ rvm:2.0.0 }
|
207
|
+
]}
|
208
|
+
it { should eq expected }
|
209
|
+
end
|
210
|
+
|
211
|
+
def format_values(values)
|
212
|
+
values.map{|i| i.map(&:to_s).sort }.sort
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|