gemika 0.3.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/test.yml +122 -0
- data/.gitignore +1 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +75 -0
- data/{gemfiles/Gemfile.3.2.mysql2 → Gemfile.3.2.mysql2} +3 -2
- data/{gemfiles/Gemfile.3.2.mysql2.lock → Gemfile.3.2.mysql2.lock} +19 -5
- data/{gemfiles/Gemfile.4.2.mysql2 → Gemfile.4.2.mysql2} +3 -2
- data/{gemfiles/Gemfile.4.2.mysql2.lock → Gemfile.4.2.mysql2.lock} +11 -4
- data/{gemfiles/Gemfile.4.2.pg → Gemfile.4.2.pg} +2 -1
- data/{gemfiles/Gemfile.4.2.pg.lock → Gemfile.4.2.pg.lock} +9 -3
- data/{gemfiles/Gemfile.5.0.mysql2 → Gemfile.5.2.mysql2} +4 -3
- data/{gemfiles/Gemfile.5.0.mysql2.lock → Gemfile.5.2.mysql2.lock} +28 -20
- data/{gemfiles/Gemfile.5.0.pg → Gemfile.5.2.pg} +3 -2
- data/{gemfiles/Gemfile.5.0.pg.lock → Gemfile.5.2.pg.lock} +26 -18
- data/Gemfile.5.2.sqlite3 +17 -0
- data/Gemfile.5.2.sqlite3.lock +67 -0
- data/Gemfile.6.0.pg +17 -0
- data/Gemfile.6.0.pg.lock +67 -0
- data/README.md +144 -71
- data/gemika.gemspec +2 -2
- data/lib/gemika/database.rb +13 -3
- data/lib/gemika/env.rb +6 -0
- data/lib/gemika/errors.rb +2 -0
- data/lib/gemika/github_actions_generator.rb +150 -0
- data/lib/gemika/matrix.rb +38 -33
- data/lib/gemika/matrix/github_actions_config.rb +61 -0
- data/lib/gemika/matrix/travis_config.rb +42 -0
- data/lib/gemika/tasks.rb +1 -0
- data/lib/gemika/tasks/gemika.rb +14 -0
- data/lib/gemika/tasks/matrix.rb +4 -4
- data/lib/gemika/version.rb +1 -1
- data/spec/fixtures/github_actions_yml/Gemfile_without_gemika +1 -0
- data/spec/fixtures/github_actions_yml/excludes.yml +13 -0
- data/spec/fixtures/github_actions_yml/gemfile_without_gemika.yml +8 -0
- data/spec/fixtures/github_actions_yml/includes.yml +20 -0
- data/spec/fixtures/github_actions_yml/invalid.yml +8 -0
- data/spec/fixtures/github_actions_yml/missing_gemfile.yml +8 -0
- data/spec/fixtures/github_actions_yml/multiple_jobs.yml +16 -0
- data/spec/fixtures/github_actions_yml/two_by_two.yml +10 -0
- data/spec/fixtures/migrate/expected_github_actions.yml +129 -0
- data/spec/fixtures/migrate/travis.yml +66 -0
- data/spec/fixtures/travis_yml/includes.yml +12 -0
- data/spec/gemika/matrix_spec.rb +116 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/support/database.github.yml +13 -0
- metadata +35 -19
- data/.travis.yml +0 -58
- data/gemfiles/Gemfile.2.3.mysql2 +0 -17
- data/gemfiles/Gemfile.2.3.mysql2.lock +0 -34
- data/spec/support/database.travis.yml +0 -9
- data/spec/support/database.yml +0 -10
data/gemika.gemspec
CHANGED
@@ -11,8 +11,8 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.description = s.summary
|
12
12
|
s.license = 'MIT'
|
13
13
|
|
14
|
-
s.files = `git ls-files`.split("\n").reject { |path| File.lstat(path).symlink? }
|
15
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n").reject { |path| File.lstat(path).symlink? }
|
14
|
+
s.files = `git ls-files`.split("\n").reject { |path| !File.exists?(path) || File.lstat(path).symlink? }
|
15
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n").reject { |path| !File.exists?(path) || File.lstat(path).symlink? }
|
16
16
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
17
|
s.require_paths = ["lib"]
|
18
18
|
end
|
data/lib/gemika/database.rb
CHANGED
@@ -14,13 +14,19 @@ module Gemika
|
|
14
14
|
|
15
15
|
def initialize(options = {})
|
16
16
|
yaml_config_folder = options.fetch(:config_folder, 'spec/support')
|
17
|
-
yaml_config_filename = Env.travis?
|
17
|
+
yaml_config_filename = if Env.travis?
|
18
|
+
'database.travis.yml'
|
19
|
+
elsif Env.github?
|
20
|
+
'database.github.yml'
|
21
|
+
else
|
22
|
+
'database.yml'
|
23
|
+
end
|
18
24
|
yaml_config_path = File.join(yaml_config_folder, yaml_config_filename)
|
19
25
|
if File.exists?(yaml_config_path)
|
20
26
|
@yaml_config = YAML.load_file(yaml_config_path)
|
21
27
|
else
|
22
|
-
warn "No database configuration in #{yaml_config_path}, using defaults: #{adapter_config.inspect}"
|
23
28
|
@yaml_config = {}
|
29
|
+
warn "No database configuration in #{yaml_config_path}, using defaults: #{adapter_config.inspect}"
|
24
30
|
end
|
25
31
|
@connected = false
|
26
32
|
end
|
@@ -95,8 +101,12 @@ module Gemika
|
|
95
101
|
default_config['username'] = 'travis' if Env.travis?
|
96
102
|
default_config['encoding'] = 'utf8'
|
97
103
|
user_config = (@yaml_config['mysql'] || @yaml_config['mysql2']) || {}
|
104
|
+
elsif Env.gem?('sqlite3')
|
105
|
+
default_config['adapter'] = 'sqlite3'
|
106
|
+
default_config['database'] = ':memory:'
|
107
|
+
user_config = (@yaml_config['sqlite'] || @yaml_config['sqlite3']) || {}
|
98
108
|
else
|
99
|
-
raise UnknownAdapter, "Unknown database type. Either 'pg' or '
|
109
|
+
raise UnknownAdapter, "Unknown database type. Either 'pg', 'mysql2', or 'sqlite3' gem should be in your current bundle."
|
100
110
|
end
|
101
111
|
default_config.merge(user_config)
|
102
112
|
end
|
data/lib/gemika/env.rb
CHANGED
@@ -87,6 +87,12 @@ module Gemika
|
|
87
87
|
!!ENV['TRAVIS']
|
88
88
|
end
|
89
89
|
|
90
|
+
##
|
91
|
+
# Return whether this process is running within a Github Actions build.
|
92
|
+
def github?
|
93
|
+
ENV.key?('GITHUB_WORKFLOW')
|
94
|
+
end
|
95
|
+
|
90
96
|
##
|
91
97
|
# Creates an hash that enumerates entries in order of insertion.
|
92
98
|
#
|
data/lib/gemika/errors.rb
CHANGED
@@ -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
|
data/lib/gemika/matrix.rb
CHANGED
@@ -1,43 +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
|
-
excludes = matrix_options.fetch('exclude', [])
|
23
|
-
rows = []
|
24
|
-
rubies.each do |ruby|
|
25
|
-
gemfiles.each do |gemfile|
|
26
|
-
row = { 'rvm' => ruby, 'gemfile' => gemfile }
|
27
|
-
rows << row unless excludes.include?(row)
|
28
|
-
end
|
29
|
-
end
|
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
10
|
##
|
42
11
|
# A row in the test matrix
|
43
12
|
#
|
@@ -125,6 +94,25 @@ module Gemika
|
|
125
94
|
print_summary
|
126
95
|
end
|
127
96
|
|
97
|
+
|
98
|
+
##
|
99
|
+
# Builds a {Matrix} from a `.travis.yml` file, or falls back to a Github Action .yml file
|
100
|
+
#
|
101
|
+
# @param [Hash] options
|
102
|
+
# @option options [String] Path to the `.travis.yml` file.
|
103
|
+
#
|
104
|
+
def self.from_ci_config
|
105
|
+
travis_location = '.travis.yml'
|
106
|
+
workflow_location = '.github/workflows/test.yml'
|
107
|
+
if File.exists?(travis_location)
|
108
|
+
from_travis_yml(:path => travis_location)
|
109
|
+
elsif File.exists?(workflow_location)
|
110
|
+
from_github_actions_yml(:path => workflow_location)
|
111
|
+
else
|
112
|
+
raise MissingMatrixDefinition, "expected either a #{travis_location} or a #{workflow_location}"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
128
116
|
##
|
129
117
|
# Builds a {Matrix} from the given `.travis.yml` file.
|
130
118
|
#
|
@@ -136,8 +124,25 @@ module Gemika
|
|
136
124
|
new(options.merge(:rows => rows))
|
137
125
|
end
|
138
126
|
|
127
|
+
##
|
128
|
+
# Builds a {Matrix} from the given Github Action workflow definition
|
129
|
+
#
|
130
|
+
# @param [Hash] options
|
131
|
+
# @option options [String] Path to the `.yml` file.
|
132
|
+
#
|
133
|
+
def self.from_github_actions_yml(options = {})
|
134
|
+
rows = GithubActionsConfig.load_rows(options)
|
135
|
+
new(options.merge(:rows => rows))
|
136
|
+
end
|
137
|
+
|
139
138
|
attr_reader :rows, :current_ruby
|
140
139
|
|
140
|
+
def self.generate_github_actions_workflow(options= {})
|
141
|
+
require 'gemika/github_actions_generator'
|
142
|
+
rows = TravisConfig.load_rows(options)
|
143
|
+
GithubActionsGenerator.new(bundler_version: Bundler::VERSION).generate(rows)
|
144
|
+
end
|
145
|
+
|
141
146
|
private
|
142
147
|
|
143
148
|
def puts(*args)
|
@@ -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/tasks.rb
CHANGED
@@ -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
|
data/lib/gemika/tasks/matrix.rb
CHANGED
@@ -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.
|
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.
|
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.
|
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.
|
38
|
+
Gemika::Matrix.from_ci_config.each do |row|
|
39
39
|
system("bundle update #{options[:gems]}")
|
40
40
|
end
|
41
41
|
end
|