kubeclient 4.6.0 → 4.9.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of kubeclient might be problematic. Click here for more details.

Files changed (116) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/actions.yml +35 -0
  3. data/CHANGELOG.md +37 -0
  4. data/README.md +155 -37
  5. data/RELEASING.md +3 -1
  6. data/kubeclient.gemspec +5 -4
  7. data/lib/kubeclient.rb +1 -1
  8. data/lib/kubeclient/common.rb +35 -6
  9. data/lib/kubeclient/config.rb +17 -4
  10. data/lib/kubeclient/exec_credentials.rb +33 -4
  11. data/lib/kubeclient/google_application_default_credentials.rb +6 -1
  12. data/lib/kubeclient/version.rb +1 -1
  13. metadata +13 -217
  14. data/.travis.yml +0 -26
  15. data/test/cassettes/kubernetes_guestbook.yml +0 -879
  16. data/test/config/allinone.kubeconfig +0 -20
  17. data/test/config/execauth.kubeconfig +0 -62
  18. data/test/config/external-ca.pem +0 -18
  19. data/test/config/external-cert.pem +0 -19
  20. data/test/config/external-key.rsa +0 -27
  21. data/test/config/external.kubeconfig +0 -20
  22. data/test/config/gcpauth.kubeconfig +0 -22
  23. data/test/config/gcpcmdauth.kubeconfig +0 -26
  24. data/test/config/nouser.kubeconfig +0 -16
  25. data/test/config/oidcauth.kubeconfig +0 -25
  26. data/test/config/timestamps.kubeconfig +0 -25
  27. data/test/config/userauth.kubeconfig +0 -28
  28. data/test/json/bindings_list.json +0 -10
  29. data/test/json/component_status.json +0 -17
  30. data/test/json/component_status_list.json +0 -52
  31. data/test/json/config.istio.io_api_resource_list.json +0 -679
  32. data/test/json/config_map_list.json +0 -9
  33. data/test/json/core_api_resource_list.json +0 -181
  34. data/test/json/core_api_resource_list_without_kind.json +0 -129
  35. data/test/json/core_oapi_resource_list_without_kind.json +0 -197
  36. data/test/json/created_endpoint.json +0 -28
  37. data/test/json/created_namespace.json +0 -20
  38. data/test/json/created_secret.json +0 -16
  39. data/test/json/created_security_context_constraint.json +0 -65
  40. data/test/json/created_service.json +0 -31
  41. data/test/json/empty_pod_list.json +0 -9
  42. data/test/json/endpoint_list.json +0 -48
  43. data/test/json/entity_list.json +0 -56
  44. data/test/json/event_list.json +0 -35
  45. data/test/json/extensions_v1beta1_api_resource_list.json +0 -217
  46. data/test/json/limit_range.json +0 -23
  47. data/test/json/limit_range_list.json +0 -31
  48. data/test/json/namespace.json +0 -13
  49. data/test/json/namespace_exception.json +0 -8
  50. data/test/json/namespace_list.json +0 -32
  51. data/test/json/node.json +0 -29
  52. data/test/json/node_list.json +0 -37
  53. data/test/json/node_notice.json +0 -160
  54. data/test/json/persistent_volume.json +0 -37
  55. data/test/json/persistent_volume_claim.json +0 -32
  56. data/test/json/persistent_volume_claim_list.json +0 -40
  57. data/test/json/persistent_volume_claims_nil_items.json +0 -8
  58. data/test/json/persistent_volume_list.json +0 -45
  59. data/test/json/pod.json +0 -92
  60. data/test/json/pod_list.json +0 -79
  61. data/test/json/pod_template_list.json +0 -9
  62. data/test/json/pods_1.json +0 -265
  63. data/test/json/pods_2.json +0 -102
  64. data/test/json/pods_410.json +0 -9
  65. data/test/json/processed_template.json +0 -27
  66. data/test/json/replication_controller.json +0 -57
  67. data/test/json/replication_controller_list.json +0 -66
  68. data/test/json/resource_quota.json +0 -46
  69. data/test/json/resource_quota_list.json +0 -54
  70. data/test/json/secret_list.json +0 -44
  71. data/test/json/security.openshift.io_api_resource_list.json +0 -69
  72. data/test/json/security_context_constraint_list.json +0 -375
  73. data/test/json/service.json +0 -33
  74. data/test/json/service_account.json +0 -25
  75. data/test/json/service_account_list.json +0 -82
  76. data/test/json/service_illegal_json_404.json +0 -1
  77. data/test/json/service_json_patch.json +0 -26
  78. data/test/json/service_list.json +0 -97
  79. data/test/json/service_merge_patch.json +0 -26
  80. data/test/json/service_patch.json +0 -25
  81. data/test/json/service_update.json +0 -22
  82. data/test/json/template.json +0 -27
  83. data/test/json/template.openshift.io_api_resource_list.json +0 -75
  84. data/test/json/template_list.json +0 -35
  85. data/test/json/versions_list.json +0 -6
  86. data/test/json/watch_stream.json +0 -3
  87. data/test/test_common.rb +0 -95
  88. data/test/test_component_status.rb +0 -29
  89. data/test/test_config.rb +0 -222
  90. data/test/test_endpoint.rb +0 -54
  91. data/test/test_exec_credentials.rb +0 -125
  92. data/test/test_gcp_command_credentials.rb +0 -27
  93. data/test/test_google_application_default_credentials.rb +0 -15
  94. data/test/test_guestbook_go.rb +0 -235
  95. data/test/test_helper.rb +0 -18
  96. data/test/test_kubeclient.rb +0 -881
  97. data/test/test_limit_range.rb +0 -25
  98. data/test/test_missing_methods.rb +0 -80
  99. data/test/test_namespace.rb +0 -59
  100. data/test/test_node.rb +0 -70
  101. data/test/test_oidc_auth_provider.rb +0 -103
  102. data/test/test_persistent_volume.rb +0 -29
  103. data/test/test_persistent_volume_claim.rb +0 -28
  104. data/test/test_pod.rb +0 -81
  105. data/test/test_pod_log.rb +0 -157
  106. data/test/test_process_template.rb +0 -80
  107. data/test/test_replication_controller.rb +0 -47
  108. data/test/test_resource_list_without_kind.rb +0 -78
  109. data/test/test_resource_quota.rb +0 -23
  110. data/test/test_secret.rb +0 -62
  111. data/test/test_security_context_constraint.rb +0 -62
  112. data/test/test_service.rb +0 -330
  113. data/test/test_service_account.rb +0 -26
  114. data/test/test_watch.rb +0 -195
  115. data/test/txt/pod_log.txt +0 -6
  116. data/test/valid_token_file +0 -1
@@ -30,7 +30,12 @@ module Kubeclient
30
30
 
31
31
  # Builds Config instance by parsing given file, with lookups relative to file's directory.
32
32
  def self.read(filename)
33
- parsed = YAML.safe_load(File.read(filename), [Date, Time])
33
+ parsed =
34
+ if RUBY_VERSION >= '2.6'
35
+ YAML.safe_load(File.read(filename), permitted_classes: [Date, Time])
36
+ else
37
+ YAML.safe_load(File.read(filename), [Date, Time])
38
+ end
34
39
  Config.new(parsed, File.dirname(filename))
35
40
  end
36
41
 
@@ -41,6 +46,11 @@ module Kubeclient
41
46
  def context(context_name = nil)
42
47
  cluster, user, namespace = fetch_context(context_name || @kcfg['current-context'])
43
48
 
49
+ if user.key?('exec')
50
+ exec_opts = expand_command_option(user['exec'], 'command')
51
+ user['exec_result'] = ExecCredentials.run(exec_opts)
52
+ end
53
+
44
54
  ca_cert_data = fetch_cluster_ca_data(cluster)
45
55
  client_cert_data = fetch_user_cert_data(user)
46
56
  client_key_data = fetch_user_key_data(user)
@@ -134,6 +144,8 @@ module Kubeclient
134
144
  File.read(ext_file_path(user['client-certificate']))
135
145
  elsif user.key?('client-certificate-data')
136
146
  Base64.decode64(user['client-certificate-data'])
147
+ elsif user.key?('exec_result') && user['exec_result'].key?('clientCertificateData')
148
+ user['exec_result']['clientCertificateData']
137
149
  end
138
150
  end
139
151
 
@@ -142,6 +154,8 @@ module Kubeclient
142
154
  File.read(ext_file_path(user['client-key']))
143
155
  elsif user.key?('client-key-data')
144
156
  Base64.decode64(user['client-key-data'])
157
+ elsif user.key?('exec_result') && user['exec_result'].key?('clientKeyData')
158
+ user['exec_result']['clientKeyData']
145
159
  end
146
160
  end
147
161
 
@@ -149,9 +163,8 @@ module Kubeclient
149
163
  options = {}
150
164
  if user.key?('token')
151
165
  options[:bearer_token] = user['token']
152
- elsif user.key?('exec')
153
- exec_opts = expand_command_option(user['exec'], 'command')
154
- options[:bearer_token] = Kubeclient::ExecCredentials.token(exec_opts)
166
+ elsif user.key?('exec_result') && user['exec_result'].key?('token')
167
+ options[:bearer_token] = user['exec_result']['token']
155
168
  elsif user.key?('auth-provider')
156
169
  options[:bearer_token] = fetch_token_from_provider(user['auth-provider'])
157
170
  else
@@ -6,7 +6,7 @@ module Kubeclient
6
6
  # Inspired by https://github.com/kubernetes/client-go/blob/master/plugin/pkg/client/auth/exec/exec.go
7
7
  class ExecCredentials
8
8
  class << self
9
- def token(opts)
9
+ def run(opts)
10
10
  require 'open3'
11
11
  require 'json'
12
12
 
@@ -25,7 +25,7 @@ module Kubeclient
25
25
 
26
26
  creds = JSON.parse(out)
27
27
  validate_credentials(opts, creds)
28
- creds['status']['token']
28
+ creds['status']
29
29
  end
30
30
 
31
31
  private
@@ -34,6 +34,36 @@ module Kubeclient
34
34
  raise KeyError, 'exec command is required' unless opts['command']
35
35
  end
36
36
 
37
+ def validate_client_credentials_status(status)
38
+ has_client_cert_data = status.key?('clientCertificateData')
39
+ has_client_key_data = status.key?('clientKeyData')
40
+
41
+ if has_client_cert_data && !has_client_key_data
42
+ raise 'exec plugin didn\'t return client key data'
43
+ end
44
+
45
+ if !has_client_cert_data && has_client_key_data
46
+ raise 'exec plugin didn\'t return client certificate data'
47
+ end
48
+
49
+ has_client_cert_data && has_client_key_data
50
+ end
51
+
52
+ def validate_credentials_status(status)
53
+ raise 'exec plugin didn\'t return a status field' if status.nil?
54
+
55
+ has_client_credentials = validate_client_credentials_status(status)
56
+ has_token = status.key?('token')
57
+
58
+ if has_client_credentials && has_token
59
+ raise 'exec plugin returned both token and client data'
60
+ end
61
+
62
+ return if has_client_credentials || has_token
63
+
64
+ raise 'exec plugin didn\'t return a token or client data' unless has_token
65
+ end
66
+
37
67
  def validate_credentials(opts, creds)
38
68
  # out should have ExecCredential structure
39
69
  raise 'invalid credentials' if creds.nil?
@@ -45,8 +75,7 @@ module Kubeclient
45
75
  "plugin returned version #{creds['apiVersion']}"
46
76
  end
47
77
 
48
- raise 'exec plugin didn\'t return a status field' if creds['status'].nil?
49
- raise 'exec plugin didn\'t return a token' if creds['status']['token'].nil?
78
+ validate_credentials_status(creds['status'])
50
79
  end
51
80
 
52
81
  # Transform name/value pairs to hash
@@ -16,7 +16,12 @@ module Kubeclient
16
16
  'googleauth gem. To support auth-provider gcp, you must include it in your ' \
17
17
  "calling application. Failed with: #{e.message}"
18
18
  end
19
- scopes = ['https://www.googleapis.com/auth/cloud-platform']
19
+
20
+ scopes = [
21
+ 'https://www.googleapis.com/auth/cloud-platform',
22
+ 'https://www.googleapis.com/auth/userinfo.email'
23
+ ]
24
+
20
25
  authorization = Google::Auth.get_application_default(scopes)
21
26
  authorization.apply({})
22
27
  authorization.access_token
@@ -1,4 +1,4 @@
1
1
  # Kubernetes REST-API Client
2
2
  module Kubeclient
3
- VERSION = '4.6.0'.freeze
3
+ VERSION = '4.9.2'.freeze
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kubeclient
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.6.0
4
+ version: 4.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alissa Bonas
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-12-30 00:00:00.000000000 Z
11
+ date: 2021-05-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -157,7 +157,7 @@ dependencies:
157
157
  - - "~>"
158
158
  - !ruby/object:Gem::Version
159
159
  version: '1.0'
160
- type: :development
160
+ type: :runtime
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
@@ -184,20 +184,20 @@ dependencies:
184
184
  requirements:
185
185
  - - "~>"
186
186
  - !ruby/object:Gem::Version
187
- version: '1.0'
187
+ version: '1.1'
188
188
  - - ">="
189
189
  - !ruby/object:Gem::Version
190
- version: 1.0.4
190
+ version: 1.1.1
191
191
  type: :runtime
192
192
  prerelease: false
193
193
  version_requirements: !ruby/object:Gem::Requirement
194
194
  requirements:
195
195
  - - "~>"
196
196
  - !ruby/object:Gem::Version
197
- version: '1.0'
197
+ version: '1.1'
198
198
  - - ">="
199
199
  - !ruby/object:Gem::Version
200
- version: 1.0.4
200
+ version: 1.1.1
201
201
  - !ruby/object:Gem::Dependency
202
202
  name: http
203
203
  requirement: !ruby/object:Gem::Requirement
@@ -225,9 +225,9 @@ executables: []
225
225
  extensions: []
226
226
  extra_rdoc_files: []
227
227
  files:
228
+ - ".github/workflows/actions.yml"
228
229
  - ".gitignore"
229
230
  - ".rubocop.yml"
230
- - ".travis.yml"
231
231
  - CHANGELOG.md
232
232
  - Gemfile
233
233
  - LICENSE.txt
@@ -251,113 +251,11 @@ files:
251
251
  - lib/kubeclient/resource_not_found_error.rb
252
252
  - lib/kubeclient/version.rb
253
253
  - lib/kubeclient/watch_stream.rb
254
- - test/cassettes/kubernetes_guestbook.yml
255
- - test/config/allinone.kubeconfig
256
- - test/config/execauth.kubeconfig
257
- - test/config/external-ca.pem
258
- - test/config/external-cert.pem
259
- - test/config/external-key.rsa
260
- - test/config/external.kubeconfig
261
- - test/config/gcpauth.kubeconfig
262
- - test/config/gcpcmdauth.kubeconfig
263
- - test/config/nouser.kubeconfig
264
- - test/config/oidcauth.kubeconfig
265
- - test/config/timestamps.kubeconfig
266
- - test/config/userauth.kubeconfig
267
- - test/json/bindings_list.json
268
- - test/json/component_status.json
269
- - test/json/component_status_list.json
270
- - test/json/config.istio.io_api_resource_list.json
271
- - test/json/config_map_list.json
272
- - test/json/core_api_resource_list.json
273
- - test/json/core_api_resource_list_without_kind.json
274
- - test/json/core_oapi_resource_list_without_kind.json
275
- - test/json/created_endpoint.json
276
- - test/json/created_namespace.json
277
- - test/json/created_secret.json
278
- - test/json/created_security_context_constraint.json
279
- - test/json/created_service.json
280
- - test/json/empty_pod_list.json
281
- - test/json/endpoint_list.json
282
- - test/json/entity_list.json
283
- - test/json/event_list.json
284
- - test/json/extensions_v1beta1_api_resource_list.json
285
- - test/json/limit_range.json
286
- - test/json/limit_range_list.json
287
- - test/json/namespace.json
288
- - test/json/namespace_exception.json
289
- - test/json/namespace_list.json
290
- - test/json/node.json
291
- - test/json/node_list.json
292
- - test/json/node_notice.json
293
- - test/json/persistent_volume.json
294
- - test/json/persistent_volume_claim.json
295
- - test/json/persistent_volume_claim_list.json
296
- - test/json/persistent_volume_claims_nil_items.json
297
- - test/json/persistent_volume_list.json
298
- - test/json/pod.json
299
- - test/json/pod_list.json
300
- - test/json/pod_template_list.json
301
- - test/json/pods_1.json
302
- - test/json/pods_2.json
303
- - test/json/pods_410.json
304
- - test/json/processed_template.json
305
- - test/json/replication_controller.json
306
- - test/json/replication_controller_list.json
307
- - test/json/resource_quota.json
308
- - test/json/resource_quota_list.json
309
- - test/json/secret_list.json
310
- - test/json/security.openshift.io_api_resource_list.json
311
- - test/json/security_context_constraint_list.json
312
- - test/json/service.json
313
- - test/json/service_account.json
314
- - test/json/service_account_list.json
315
- - test/json/service_illegal_json_404.json
316
- - test/json/service_json_patch.json
317
- - test/json/service_list.json
318
- - test/json/service_merge_patch.json
319
- - test/json/service_patch.json
320
- - test/json/service_update.json
321
- - test/json/template.json
322
- - test/json/template.openshift.io_api_resource_list.json
323
- - test/json/template_list.json
324
- - test/json/versions_list.json
325
- - test/json/watch_stream.json
326
- - test/test_common.rb
327
- - test/test_component_status.rb
328
- - test/test_config.rb
329
- - test/test_endpoint.rb
330
- - test/test_exec_credentials.rb
331
- - test/test_gcp_command_credentials.rb
332
- - test/test_google_application_default_credentials.rb
333
- - test/test_guestbook_go.rb
334
- - test/test_helper.rb
335
- - test/test_kubeclient.rb
336
- - test/test_limit_range.rb
337
- - test/test_missing_methods.rb
338
- - test/test_namespace.rb
339
- - test/test_node.rb
340
- - test/test_oidc_auth_provider.rb
341
- - test/test_persistent_volume.rb
342
- - test/test_persistent_volume_claim.rb
343
- - test/test_pod.rb
344
- - test/test_pod_log.rb
345
- - test/test_process_template.rb
346
- - test/test_replication_controller.rb
347
- - test/test_resource_list_without_kind.rb
348
- - test/test_resource_quota.rb
349
- - test/test_secret.rb
350
- - test/test_security_context_constraint.rb
351
- - test/test_service.rb
352
- - test/test_service_account.rb
353
- - test/test_watch.rb
354
- - test/txt/pod_log.txt
355
- - test/valid_token_file
356
254
  homepage: https://github.com/abonas/kubeclient
357
255
  licenses:
358
256
  - MIT
359
257
  metadata: {}
360
- post_install_message:
258
+ post_install_message:
361
259
  rdoc_options: []
362
260
  require_paths:
363
261
  - lib
@@ -372,110 +270,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
372
270
  - !ruby/object:Gem::Version
373
271
  version: '0'
374
272
  requirements: []
375
- rubygems_version: 3.0.3
376
- signing_key:
273
+ rubygems_version: 3.2.3
274
+ signing_key:
377
275
  specification_version: 4
378
276
  summary: A client for Kubernetes REST api
379
- test_files:
380
- - test/cassettes/kubernetes_guestbook.yml
381
- - test/config/allinone.kubeconfig
382
- - test/config/execauth.kubeconfig
383
- - test/config/external-ca.pem
384
- - test/config/external-cert.pem
385
- - test/config/external-key.rsa
386
- - test/config/external.kubeconfig
387
- - test/config/gcpauth.kubeconfig
388
- - test/config/gcpcmdauth.kubeconfig
389
- - test/config/nouser.kubeconfig
390
- - test/config/oidcauth.kubeconfig
391
- - test/config/timestamps.kubeconfig
392
- - test/config/userauth.kubeconfig
393
- - test/json/bindings_list.json
394
- - test/json/component_status.json
395
- - test/json/component_status_list.json
396
- - test/json/config.istio.io_api_resource_list.json
397
- - test/json/config_map_list.json
398
- - test/json/core_api_resource_list.json
399
- - test/json/core_api_resource_list_without_kind.json
400
- - test/json/core_oapi_resource_list_without_kind.json
401
- - test/json/created_endpoint.json
402
- - test/json/created_namespace.json
403
- - test/json/created_secret.json
404
- - test/json/created_security_context_constraint.json
405
- - test/json/created_service.json
406
- - test/json/empty_pod_list.json
407
- - test/json/endpoint_list.json
408
- - test/json/entity_list.json
409
- - test/json/event_list.json
410
- - test/json/extensions_v1beta1_api_resource_list.json
411
- - test/json/limit_range.json
412
- - test/json/limit_range_list.json
413
- - test/json/namespace.json
414
- - test/json/namespace_exception.json
415
- - test/json/namespace_list.json
416
- - test/json/node.json
417
- - test/json/node_list.json
418
- - test/json/node_notice.json
419
- - test/json/persistent_volume.json
420
- - test/json/persistent_volume_claim.json
421
- - test/json/persistent_volume_claim_list.json
422
- - test/json/persistent_volume_claims_nil_items.json
423
- - test/json/persistent_volume_list.json
424
- - test/json/pod.json
425
- - test/json/pod_list.json
426
- - test/json/pod_template_list.json
427
- - test/json/pods_1.json
428
- - test/json/pods_2.json
429
- - test/json/pods_410.json
430
- - test/json/processed_template.json
431
- - test/json/replication_controller.json
432
- - test/json/replication_controller_list.json
433
- - test/json/resource_quota.json
434
- - test/json/resource_quota_list.json
435
- - test/json/secret_list.json
436
- - test/json/security.openshift.io_api_resource_list.json
437
- - test/json/security_context_constraint_list.json
438
- - test/json/service.json
439
- - test/json/service_account.json
440
- - test/json/service_account_list.json
441
- - test/json/service_illegal_json_404.json
442
- - test/json/service_json_patch.json
443
- - test/json/service_list.json
444
- - test/json/service_merge_patch.json
445
- - test/json/service_patch.json
446
- - test/json/service_update.json
447
- - test/json/template.json
448
- - test/json/template.openshift.io_api_resource_list.json
449
- - test/json/template_list.json
450
- - test/json/versions_list.json
451
- - test/json/watch_stream.json
452
- - test/test_common.rb
453
- - test/test_component_status.rb
454
- - test/test_config.rb
455
- - test/test_endpoint.rb
456
- - test/test_exec_credentials.rb
457
- - test/test_gcp_command_credentials.rb
458
- - test/test_google_application_default_credentials.rb
459
- - test/test_guestbook_go.rb
460
- - test/test_helper.rb
461
- - test/test_kubeclient.rb
462
- - test/test_limit_range.rb
463
- - test/test_missing_methods.rb
464
- - test/test_namespace.rb
465
- - test/test_node.rb
466
- - test/test_oidc_auth_provider.rb
467
- - test/test_persistent_volume.rb
468
- - test/test_persistent_volume_claim.rb
469
- - test/test_pod.rb
470
- - test/test_pod_log.rb
471
- - test/test_process_template.rb
472
- - test/test_replication_controller.rb
473
- - test/test_resource_list_without_kind.rb
474
- - test/test_resource_quota.rb
475
- - test/test_secret.rb
476
- - test/test_security_context_constraint.rb
477
- - test/test_service.rb
478
- - test/test_service_account.rb
479
- - test/test_watch.rb
480
- - test/txt/pod_log.txt
481
- - test/valid_token_file
277
+ test_files: []
data/.travis.yml DELETED
@@ -1,26 +0,0 @@
1
- language: ruby
2
- sudo: false
3
- cache: bundler
4
- script: bundle exec rake $TASK
5
-
6
- os:
7
- - linux
8
- - osx
9
- rvm:
10
- - "2.2.0"
11
- - "2.3.0"
12
- - "2.4.0"
13
- - "2.5.0"
14
- - "2.6.3"
15
- env:
16
- - TASK=test
17
- matrix:
18
- exclude:
19
- - os: osx
20
- rvm: "2.2.0"
21
- - os: osx
22
- rvm: "2.3.0"
23
- include:
24
- - os: linux
25
- rvm: "2.5.0"
26
- env: TASK=rubocop