gemika 0.4.1 → 0.7.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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +112 -0
  3. data/.ruby-version +1 -1
  4. data/CHANGELOG.md +31 -4
  5. data/Gemfile.5.2.mysql2 +1 -1
  6. data/Gemfile.5.2.mysql2.lock +4 -4
  7. data/Gemfile.5.2.pg.lock +2 -2
  8. data/Gemfile.5.2.sqlite3.lock +2 -2
  9. data/{Gemfile.6.0.pg → Gemfile.6.1.pg} +2 -2
  10. data/{Gemfile.6.0.pg.lock → Gemfile.6.1.pg.lock} +21 -22
  11. data/{Gemfile.4.2.pg → Gemfile.7.0.pg} +3 -5
  12. data/Gemfile.7.0.pg.lock +64 -0
  13. data/README.md +77 -7
  14. data/lib/gemika/database.rb +2 -2
  15. data/lib/gemika/env.rb +9 -1
  16. data/lib/gemika/errors.rb +2 -0
  17. data/lib/gemika/github_actions_generator.rb +150 -0
  18. data/lib/gemika/matrix/github_actions_config.rb +61 -0
  19. data/lib/gemika/matrix/travis_config.rb +42 -0
  20. data/lib/gemika/matrix.rb +109 -42
  21. data/lib/gemika/tasks/gemika.rb +14 -0
  22. data/lib/gemika/tasks/matrix.rb +4 -4
  23. data/lib/gemika/tasks.rb +1 -0
  24. data/lib/gemika/version.rb +1 -1
  25. data/spec/fixtures/github_actions_yml/Gemfile_without_gemika +1 -0
  26. data/spec/fixtures/github_actions_yml/excludes.yml +13 -0
  27. data/spec/fixtures/github_actions_yml/gemfile_without_gemika.yml +8 -0
  28. data/spec/fixtures/github_actions_yml/includes.yml +20 -0
  29. data/spec/fixtures/github_actions_yml/invalid.yml +8 -0
  30. data/spec/fixtures/github_actions_yml/missing_gemfile.yml +8 -0
  31. data/spec/fixtures/github_actions_yml/multiple_jobs.yml +16 -0
  32. data/spec/fixtures/github_actions_yml/two_by_two.yml +10 -0
  33. data/spec/fixtures/migrate/expected_github_actions.yml +129 -0
  34. data/{.travis.yml → spec/fixtures/migrate/travis.yml} +1 -1
  35. data/spec/gemika/matrix/row_spec.rb +62 -0
  36. data/spec/gemika/matrix_spec.rb +100 -0
  37. data/spec/spec_helper.rb +5 -1
  38. data/spec/support/database.github.yml +13 -0
  39. metadata +24 -15
  40. data/Gemfile.2.3.mysql2 +0 -18
  41. data/Gemfile.2.3.mysql2.lock +0 -42
  42. data/Gemfile.3.2.mysql2 +0 -18
  43. data/Gemfile.3.2.mysql2.lock +0 -67
  44. data/Gemfile.4.2.mysql2 +0 -17
  45. data/Gemfile.4.2.mysql2.lock +0 -69
  46. data/Gemfile.4.2.pg.lock +0 -69
  47. data/spec/support/database.travis.yml +0 -9
@@ -0,0 +1,150 @@
1
+ module Gemika
2
+ class GithubActionsGenerator
3
+ TYPES = {
4
+ test_sqlite: {
5
+ gemfile_filter: /\.sqlite/,
6
+ },
7
+ test_pg: {
8
+ gemfile_filter: /\.pg/,
9
+ database_setup: [
10
+ 'sudo apt-get install -y postgresql-client',
11
+ "PGPASSWORD=postgres psql -c 'create database test;' -U postgres -p 5432 -h localhost",
12
+ ],
13
+ services: {
14
+ 'postgres' => {
15
+ 'image' => 'postgres',
16
+ 'env' => {
17
+ 'POSTGRES_PASSWORD' => 'postgres'
18
+ },
19
+ 'options' => '--health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5',
20
+ 'ports' => ['5432:5432'],
21
+ },
22
+ },
23
+ },
24
+ test_mysql: {
25
+ gemfile_filter: /\.mysql/,
26
+ database_setup: [
27
+ 'sudo apt-get install -y mysql-client libmariadbclient-dev',
28
+ "mysql -e 'create database IF NOT EXISTS test;' -u root --password=password -P 3306 -h 127.0.0.1",
29
+ ],
30
+ services: {
31
+ 'mysql' => {
32
+ 'image' => 'mysql:5.6',
33
+ 'env' => {
34
+ 'MYSQL_ROOT_PASSWORD' => 'password',
35
+ },
36
+ 'options' => '--health-cmd "mysqladmin ping" --health-interval 10s --health-timeout 5s --health-retries 5',
37
+ 'ports' => ['3306:3306'],
38
+ },
39
+ },
40
+ },
41
+ test: {
42
+ gemfile_filter: //,
43
+ }
44
+ }
45
+
46
+ def initialize(bundler_version:)
47
+ @bundler_version = bundler_version
48
+ end
49
+
50
+ def generate(rows)
51
+ rows_by_type = split_rows_by_gemfile(rows)
52
+ jobs = {}
53
+ rows_by_type.each do |type, type_rows|
54
+ jobs[type.to_s] = job_by_type(type, type_rows)
55
+ end
56
+ full_config(jobs)
57
+ end
58
+
59
+ private
60
+
61
+ def split_rows_by_gemfile(rows)
62
+ rows.group_by do |row|
63
+ TYPES.detect do |type, type_definition|
64
+ row.gemfile =~ type_definition[:gemfile_filter]
65
+ end.first
66
+ end
67
+ end
68
+
69
+ def job_by_type(type, rows)
70
+ matrix = full_matrix(rows) || include_matrix(rows)
71
+ type_definition = TYPES[type]
72
+
73
+ steps = [{
74
+ 'uses' => 'actions/checkout@v2',
75
+ }, {
76
+ 'name' => 'Install ruby',
77
+ 'uses' => 'ruby/setup-ruby@v1',
78
+ 'with' => {'ruby-version' => '${{ matrix.ruby }}'},
79
+ }]
80
+
81
+ if (database_setup = type_definition[:database_setup])
82
+ steps << {
83
+ 'name' => 'Setup database',
84
+ 'run' => database_setup.join("\n") + "\n",
85
+ }
86
+ end
87
+
88
+ steps += [{
89
+ 'name' => 'Bundle',
90
+ 'run' => "gem install bundler:#{@bundler_version}\nbundle install --no-deployment\n",
91
+ }, {
92
+ 'name' => 'Run tests',
93
+ 'run' => 'bundle exec rspec',
94
+ }]
95
+
96
+ job = {}
97
+ job['runs-on'] = 'ubuntu-20.04'
98
+ if (services = type_definition[:services])
99
+ job['services'] = services
100
+ end
101
+ job['strategy'] = {
102
+ 'fail-fast' => false,
103
+ 'matrix' => matrix,
104
+ }
105
+ job['env'] = {
106
+ 'BUNDLE_GEMFILE' => '${{ matrix.gemfile }}',
107
+ }
108
+ job['steps'] = steps
109
+
110
+ job
111
+ end
112
+
113
+ def full_matrix(rows)
114
+ rubies = rows.map(&:ruby)
115
+ gemfiles = rows.map(&:gemfile)
116
+ if rubies.size * gemfiles.size == rows.size
117
+ {
118
+ 'ruby' => rubies,
119
+ 'gemfile' => gemfiles,
120
+ }
121
+ end
122
+ end
123
+
124
+ def include_matrix(rows)
125
+ {
126
+ 'include' => rows.map do |row|
127
+ {
128
+ 'ruby' => row.ruby,
129
+ 'gemfile' => row.gemfile,
130
+ }
131
+ end,
132
+ }
133
+ end
134
+
135
+ def full_config(jobs)
136
+ {
137
+ 'name' => 'Tests',
138
+ 'on' => {
139
+ 'push' => {
140
+ 'branches' => ['master'],
141
+ },
142
+ 'pull_request' => {
143
+ 'branches' => ['master'],
144
+ },
145
+ },
146
+ 'jobs' => jobs,
147
+ }
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,61 @@
1
+ module Gemika
2
+ class Matrix
3
+
4
+ ##
5
+ # Load Github Action `.yml` files.
6
+ #
7
+ # @!visibility private
8
+ #
9
+ class GithubActionsConfig
10
+ class << self
11
+
12
+ def load_rows(options)
13
+ path = options.fetch(:path, '.github/workflows/test.yml')
14
+ workflow_yml = YAML.load_file(path)
15
+
16
+ matrices = workflow_yml.fetch('jobs', {}).values.map do |job|
17
+ job.fetch('strategy', {})['matrix']
18
+ end.reject(&:nil?)
19
+
20
+ matrices.map do |matrix|
21
+ matrix_to_rows(matrix)
22
+ end.flatten(1)
23
+ end
24
+
25
+ private
26
+
27
+ def matrix_to_rows(matrix)
28
+ if (!matrix['ruby'] || !matrix['gemfile']) && (!matrix['include'])
29
+ raise InvalidMatrixDefinition, 'matrix must use the keys "ruby" and "gemfile"'
30
+ end
31
+
32
+ rubies = matrix.fetch('ruby', [])
33
+ gemfiles = matrix.fetch('gemfile', [])
34
+
35
+ includes = matrix.fetch('include', [])
36
+ excludes = matrix.fetch('exclude', [])
37
+
38
+ rows = []
39
+ rubies.each do |ruby|
40
+ gemfiles.each do |gemfile|
41
+ row = { 'ruby' => ruby, 'gemfile' => gemfile }
42
+ rows << row unless excludes.include?(row)
43
+ end
44
+ end
45
+
46
+ rows = rows + includes
47
+ rows.map { |row| convert_row(row) }
48
+ end
49
+
50
+ def convert_row(row_hash)
51
+ if !row_hash['ruby'] || !row_hash['gemfile']
52
+ raise InvalidMatrixDefinition, 'matrix must use the keys "ruby" and "gemfile"'
53
+ end
54
+ Row.new(:ruby => row_hash['ruby'], :gemfile => row_hash['gemfile'])
55
+ end
56
+
57
+ end
58
+ end
59
+
60
+ end
61
+ end
@@ -0,0 +1,42 @@
1
+ module Gemika
2
+ class Matrix
3
+
4
+ ##
5
+ # Load `.travis.yml` files.
6
+ #
7
+ # @!visibility private
8
+ #
9
+ class TravisConfig
10
+ class << self
11
+
12
+ def load_rows(options)
13
+ path = options.fetch(:path, '.travis.yml')
14
+ travis_yml = YAML.load_file(path)
15
+ rubies = travis_yml.fetch('rvm', [])
16
+ gemfiles = travis_yml.fetch('gemfile', [])
17
+ matrix_options = travis_yml.fetch('matrix', {})
18
+ includes = matrix_options.fetch('include', [])
19
+ excludes = matrix_options.fetch('exclude', [])
20
+
21
+ rows = []
22
+ rubies.each do |ruby|
23
+ gemfiles.each do |gemfile|
24
+ row = { 'rvm' => ruby, 'gemfile' => gemfile }
25
+ rows << row unless excludes.include?(row)
26
+ end
27
+ end
28
+
29
+ rows = rows + includes
30
+ rows = rows.map { |row| convert_row(row) }
31
+ rows
32
+ end
33
+
34
+ def convert_row(travis_row)
35
+ Row.new(:ruby => travis_row['rvm'], :gemfile => travis_row['gemfile'])
36
+ end
37
+
38
+ end
39
+ end
40
+
41
+ end
42
+ end
data/lib/gemika/matrix.rb CHANGED
@@ -1,47 +1,12 @@
1
1
  require 'yaml'
2
2
  require 'gemika/errors'
3
3
  require 'gemika/env'
4
+ require 'gemika/matrix/travis_config'
5
+ require 'gemika/matrix/github_actions_config'
4
6
 
5
7
  module Gemika
6
8
  class Matrix
7
9
 
8
- ##
9
- # Load `.travis.yml` files.
10
- #
11
- # @!visibility private
12
- #
13
- class TravisConfig
14
- class << self
15
-
16
- def load_rows(options)
17
- path = options.fetch(:path, '.travis.yml')
18
- travis_yml = YAML.load_file(path)
19
- rubies = travis_yml.fetch('rvm', [])
20
- gemfiles = travis_yml.fetch('gemfile', [])
21
- matrix_options = travis_yml.fetch('matrix', {})
22
- includes = matrix_options.fetch('include', [])
23
- excludes = matrix_options.fetch('exclude', [])
24
-
25
- rows = []
26
- rubies.each do |ruby|
27
- gemfiles.each do |gemfile|
28
- row = { 'rvm' => ruby, 'gemfile' => gemfile }
29
- rows << row unless excludes.include?(row)
30
- end
31
- end
32
-
33
- rows = rows + includes
34
- rows = rows.map { |row| convert_row(row) }
35
- rows
36
- end
37
-
38
- def convert_row(travis_row)
39
- Row.new(:ruby => travis_row['rvm'], :gemfile => travis_row['gemfile'])
40
- end
41
-
42
- end
43
- end
44
-
45
10
  ##
46
11
  # A row in the test matrix
47
12
  #
@@ -57,6 +22,11 @@ module Gemika
57
22
  #
58
23
  attr_reader :ruby
59
24
 
25
+ ##
26
+ # The actually used Ruby version for the row.
27
+ #
28
+ attr_reader :used_ruby
29
+
60
30
  ##
61
31
  # The path to the gemfile for the row.
62
32
  #
@@ -66,7 +36,9 @@ module Gemika
66
36
  # Returns whether this row can be run with the given Ruby version.
67
37
  #
68
38
  def compatible_with_ruby?(current_ruby = Env.ruby)
69
- ruby == current_ruby
39
+ @used_ruby = aliased_ruby(ruby)
40
+
41
+ @used_ruby == current_ruby
70
42
  end
71
43
 
72
44
  ##
@@ -80,6 +52,53 @@ module Gemika
80
52
  contents.include?('gemika') or raise UnusableGemfile, "Gemfile is missing gemika dependency: #{gemfile}"
81
53
  end
82
54
 
55
+ private
56
+
57
+ ##
58
+ # Checks if the requested ruby version is aliased by rbenv to use another ruby version.
59
+ # Returns the runnable ruby version.
60
+ #
61
+ def aliased_ruby(requested_version)
62
+ ruby_aliases = rbenv_aliases
63
+
64
+ aliased_versions = {}
65
+
66
+ ruby_aliases.split("\n").each do |ruby_alias|
67
+ split_pattern = /\A(.+) => (.+)\z/
68
+ alias_name, aliased_version = ruby_alias.match(split_pattern)&.captures
69
+ aliased_versions[alias_name] = aliased_version
70
+ end
71
+
72
+ find_aliased_ruby(requested_version, aliased_versions)
73
+ end
74
+
75
+ ##
76
+ # Recursively traverses aliases until the requested Ruby version is found.
77
+ # Returns the requested version if no alias can be found for that version.
78
+ #
79
+ def find_aliased_ruby(requested_version, aliased_versions)
80
+ found_version = aliased_versions[requested_version]
81
+
82
+ if found_version == requested_version
83
+ found_version
84
+ elsif found_version
85
+ find_aliased_ruby(found_version, aliased_versions)
86
+ else
87
+ requested_version
88
+ end
89
+ end
90
+
91
+ ##
92
+ # Returns the list of rbenv aliases, if rbenv is installed.
93
+ #
94
+ def rbenv_aliases
95
+ if `which rbenv` != ''
96
+ `rbenv alias --list`
97
+ else
98
+ ''
99
+ end
100
+ end
101
+
83
102
  end
84
103
 
85
104
  COLOR_HEAD = "\e[44;97m"
@@ -99,6 +118,7 @@ module Gemika
99
118
  @compatible_count = 0
100
119
  @all_passed = nil
101
120
  @current_ruby = options.fetch(:current_ruby, RUBY_VERSION)
121
+ @aliased_rubys = {}
102
122
  end
103
123
 
104
124
  ##
@@ -114,6 +134,9 @@ module Gemika
114
134
  gemfile = row.gemfile
115
135
  if row.compatible_with_ruby?(current_ruby)
116
136
  @compatible_count += 1
137
+
138
+ @aliased_rubys[current_ruby] = row.ruby
139
+
117
140
  print_title gemfile
118
141
  gemfile_passed = Env.with_gemfile(gemfile, row, &block)
119
142
  @all_passed &= gemfile_passed
@@ -129,6 +152,25 @@ module Gemika
129
152
  print_summary
130
153
  end
131
154
 
155
+
156
+ ##
157
+ # Builds a {Matrix} from a `.travis.yml` file, or falls back to a Github Action .yml file
158
+ #
159
+ # @param [Hash] options
160
+ # @option options [String] Path to the `.travis.yml` file.
161
+ #
162
+ def self.from_ci_config
163
+ travis_location = '.travis.yml'
164
+ workflow_location = '.github/workflows/test.yml'
165
+ if File.exists?(travis_location)
166
+ from_travis_yml(:path => travis_location)
167
+ elsif File.exists?(workflow_location)
168
+ from_github_actions_yml(:path => workflow_location)
169
+ else
170
+ raise MissingMatrixDefinition, "expected either a #{travis_location} or a #{workflow_location}"
171
+ end
172
+ end
173
+
132
174
  ##
133
175
  # Builds a {Matrix} from the given `.travis.yml` file.
134
176
  #
@@ -140,8 +182,25 @@ module Gemika
140
182
  new(options.merge(:rows => rows))
141
183
  end
142
184
 
185
+ ##
186
+ # Builds a {Matrix} from the given Github Action workflow definition
187
+ #
188
+ # @param [Hash] options
189
+ # @option options [String] Path to the `.yml` file.
190
+ #
191
+ def self.from_github_actions_yml(options = {})
192
+ rows = GithubActionsConfig.load_rows(options)
193
+ new(options.merge(:rows => rows))
194
+ end
195
+
143
196
  attr_reader :rows, :current_ruby
144
197
 
198
+ def self.generate_github_actions_workflow(options= {})
199
+ require 'gemika/github_actions_generator'
200
+ rows = TravisConfig.load_rows(options)
201
+ GithubActionsGenerator.new(bundler_version: Bundler::VERSION).generate(rows)
202
+ end
203
+
145
204
  private
146
205
 
147
206
  def puts(*args)
@@ -177,19 +236,27 @@ module Gemika
177
236
  puts
178
237
 
179
238
  if @compatible_count == 0
180
- message = "No gemfiles were compatible with Ruby #{RUBY_VERSION}"
239
+ message = "No gemfiles were compatible with Ruby #{@aliased_rubys[RUBY_VERSION]}"
181
240
  puts tint(message, COLOR_FAILURE)
182
- puts
183
241
  raise UnsupportedRuby, message
184
242
  elsif @all_passed
185
- puts tint("All gemfiles succeeded for Ruby #{RUBY_VERSION}", COLOR_SUCCESS)
186
- puts
243
+ puts tint("All gemfiles succeeded for Ruby #{@aliased_rubys[RUBY_VERSION]}", COLOR_SUCCESS)
187
244
  else
188
245
  message = 'Some gemfiles failed'
189
246
  puts tint(message, COLOR_FAILURE)
190
247
  puts
191
248
  raise MatrixFailed, message
192
249
  end
250
+
251
+ print_aliases
252
+
253
+ puts
254
+ end
255
+
256
+ def print_aliases
257
+ @aliased_rubys.select { |used_version, alias_name| used_version != alias_name }.each do |used_version, alias_name|
258
+ puts tint("Ruby #{alias_name} is an alias for Ruby #{used_version} in this environment.", COLOR_WARNING)
259
+ end
193
260
  end
194
261
 
195
262
  end
@@ -0,0 +1,14 @@
1
+ require 'gemika/env'
2
+ require 'gemika/matrix'
3
+
4
+ ##
5
+ # Rake tasks to run commands for each compatible row in the test matrix.
6
+ #
7
+ namespace :gemika do
8
+
9
+ desc "Generate a github action workflow from a .travis.yml"
10
+ task :generate_github_actions_workflow do
11
+ puts Gemika::Matrix.generate_github_actions_workflow.to_yaml
12
+ end
13
+
14
+ end
@@ -9,7 +9,7 @@ namespace :matrix do
9
9
 
10
10
  desc "Run specs for all Ruby #{RUBY_VERSION} gemfiles"
11
11
  task :spec, :files do |t, options|
12
- Gemika::Matrix.from_travis_yml.each do |row|
12
+ Gemika::Matrix.from_ci_config.each do |row|
13
13
  options = options.to_hash.merge(
14
14
  :gemfile => row.gemfile,
15
15
  :fatal => false,
@@ -21,21 +21,21 @@ namespace :matrix do
21
21
 
22
22
  desc "Install all Ruby #{RUBY_VERSION} gemfiles"
23
23
  task :install do
24
- Gemika::Matrix.from_travis_yml.each do |row|
24
+ Gemika::Matrix.from_ci_config.each do |row|
25
25
  system('bundle install')
26
26
  end
27
27
  end
28
28
 
29
29
  desc "List dependencies for all Ruby #{RUBY_VERSION} gemfiles"
30
30
  task :list do
31
- Gemika::Matrix.from_travis_yml.each do |row|
31
+ Gemika::Matrix.from_ci_config.each do |row|
32
32
  system('bundle list')
33
33
  end
34
34
  end
35
35
 
36
36
  desc "Update all Ruby #{RUBY_VERSION} gemfiles"
37
37
  task :update, :gems do |t, options|
38
- Gemika::Matrix.from_travis_yml.each do |row|
38
+ Gemika::Matrix.from_ci_config.each do |row|
39
39
  system("bundle update #{options[:gems]}")
40
40
  end
41
41
  end
data/lib/gemika/tasks.rb CHANGED
@@ -1,2 +1,3 @@
1
1
  require 'gemika/tasks/matrix'
2
2
  require 'gemika/tasks/rspec'
3
+ require 'gemika/tasks/gemika'
@@ -1,3 +1,3 @@
1
1
  module Gemika
2
- VERSION = '0.4.1'
2
+ VERSION = '0.7.0'
3
3
  end
@@ -0,0 +1 @@
1
+ gem 'some-gem'
@@ -0,0 +1,13 @@
1
+ jobs:
2
+ first_job:
3
+ strategy:
4
+ matrix:
5
+ ruby:
6
+ - "2.1.8"
7
+ - "2.3.1"
8
+ gemfile:
9
+ - gemfiles/Gemfile1
10
+ - gemfiles/Gemfile2
11
+ exclude:
12
+ - ruby: 2.1.8
13
+ gemfile: gemfiles/Gemfile1
@@ -0,0 +1,8 @@
1
+ jobs:
2
+ first_job:
3
+ strategy:
4
+ matrix:
5
+ ruby:
6
+ - 2.1.8
7
+ gemfile:
8
+ - spec/fixtures/travis_yml/Gemfile_without_gemika
@@ -0,0 +1,20 @@
1
+ matrix:
2
+ jobs:
3
+ first_job:
4
+ strategy:
5
+ matrix:
6
+ ruby:
7
+ - "2.1.8"
8
+ - "2.3.1"
9
+ gemfile:
10
+ - gemfiles/Gemfile1
11
+ - gemfiles/Gemfile2
12
+ include:
13
+ - ruby: 2.6.3
14
+ gemfile: gemfiles/Gemfile3
15
+ second_job:
16
+ strategy:
17
+ matrix:
18
+ include:
19
+ - ruby: 2.7.1
20
+ gemfile: gemfiles/Gemfile3
@@ -0,0 +1,8 @@
1
+ jobs:
2
+ first_job:
3
+ strategy:
4
+ matrix:
5
+ ruby_version:
6
+ - "2.1.8"
7
+ gemfile:
8
+ - gemfiles/Gemfile1
@@ -0,0 +1,8 @@
1
+ jobs:
2
+ first_job:
3
+ strategy:
4
+ matrix:
5
+ ruby:
6
+ - 2.1.8
7
+ gemfile:
8
+ - gemfiles/nonexisting_gemfile
@@ -0,0 +1,16 @@
1
+ jobs:
2
+ first_job:
3
+ strategy:
4
+ matrix:
5
+ ruby:
6
+ - "2.1.8"
7
+ gemfile:
8
+ - gemfiles/Gemfile1
9
+
10
+ second_job:
11
+ strategy:
12
+ matrix:
13
+ ruby:
14
+ - "2.3.1"
15
+ gemfile:
16
+ - gemfiles/Gemfile2
@@ -0,0 +1,10 @@
1
+ jobs:
2
+ first_job:
3
+ strategy:
4
+ matrix:
5
+ ruby:
6
+ - "2.1.8"
7
+ - "2.3.1"
8
+ gemfile:
9
+ - gemfiles/Gemfile1
10
+ - gemfiles/Gemfile2