cloudtasker 0.8.1 → 0.9.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +41 -0
- data/CHANGELOG.md +47 -0
- data/README.md +3 -1
- data/app/controllers/cloudtasker/worker_controller.rb +21 -3
- data/cloudtasker.gemspec +3 -3
- data/lib/cloudtasker.rb +1 -0
- data/lib/cloudtasker/backend/google_cloud_task.rb +25 -5
- data/lib/cloudtasker/cloud_task.rb +2 -0
- data/lib/cloudtasker/config.rb +16 -1
- data/lib/cloudtasker/max_task_size_exceeded_error.rb +14 -0
- data/lib/cloudtasker/redis_client.rb +5 -1
- data/lib/cloudtasker/version.rb +1 -1
- data/lib/cloudtasker/worker_handler.rb +2 -2
- metadata +17 -17
- data/.travis.yml +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4f2c05ceac2d50370d52f7135f242f949b264abfaec1f31cb755a2afac6d35dc
|
4
|
+
data.tar.gz: e64432a75782ebc4fa87edfea9b3f683f3a518a1680372a644b77b5c4df52839
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7a3a8faf52c7a91e9739d867f4fda9786e7399942b4e341fcc297940bd6ed9c1b7810e3109c38b13e555db5532794af3f1f5aa0dc7c1384678e222d1162f5796
|
7
|
+
data.tar.gz: dc2ac72de941e8b8ba617b5f1cfc85a535102b86a4476af2d1c5c8bd93953e3773077714620f8593ada54f57675532233a5a244c912b9d36407bd51dfac02db6
|
@@ -0,0 +1,41 @@
|
|
1
|
+
name: Test
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ master, 0.9-stable ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ master, 0.9-stable ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
build:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
strategy:
|
13
|
+
matrix:
|
14
|
+
ruby:
|
15
|
+
- '2.5.x'
|
16
|
+
- '2.6.x'
|
17
|
+
appraisal:
|
18
|
+
- 'google-cloud-tasks-1.0'
|
19
|
+
- 'google-cloud-tasks-1.1'
|
20
|
+
- 'google-cloud-tasks-1.2'
|
21
|
+
- 'google-cloud-tasks-1.3'
|
22
|
+
- 'rails-5.2'
|
23
|
+
- 'rails-6.0'
|
24
|
+
steps:
|
25
|
+
- name: Setup System
|
26
|
+
run: sudo apt-get install libsqlite3-dev
|
27
|
+
- uses: actions/checkout@v2
|
28
|
+
- uses: zhulik/redis-action@1.1.0
|
29
|
+
- name: Set up Ruby 2.6
|
30
|
+
uses: actions/setup-ruby@v1
|
31
|
+
with:
|
32
|
+
ruby-version: ${{ matrix.ruby }}
|
33
|
+
- name: Build and test with Rake
|
34
|
+
env:
|
35
|
+
APPRAISAL_CONTEXT: ${{ matrix.appraisal }}
|
36
|
+
run: |
|
37
|
+
gem install bundler
|
38
|
+
bundle install --jobs 4 --retry 3
|
39
|
+
bundle exec rubocop
|
40
|
+
bundle exec appraisal ${APPRAISAL_CONTEXT} bundle
|
41
|
+
bundle exec appraisal ${APPRAISAL_CONTEXT} rspec
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,52 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [v0.9.3](https://github.com/keypup-io/cloudtasker/tree/v0.9.3) (2020-06-25)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/keypup-io/cloudtasker/compare/v0.9.2...v0.9.3)
|
6
|
+
|
7
|
+
**Fixed bugs:**
|
8
|
+
- Google Cloud Tasks: lock version to `~> 1.0` (Google recently released a v2 which changes its bindings completely). An [issue](https://github.com/keypup-io/cloudtasker/issues/11) has been raised to upgrade Cloudtasker to `google-cloud-tasks` `v2`.
|
9
|
+
|
10
|
+
## [v0.9.2](https://github.com/keypup-io/cloudtasker/tree/v0.9.2) (2020-03-04)
|
11
|
+
|
12
|
+
[Full Changelog](https://github.com/keypup-io/cloudtasker/compare/v0.9.1...v0.9.2)
|
13
|
+
|
14
|
+
**Fixed bugs:**
|
15
|
+
- Cloud Task: ignore "not found" errors when trying to delete an already deleted task.
|
16
|
+
|
17
|
+
## [v0.9.1](https://github.com/keypup-io/cloudtasker/tree/v0.9.1) (2020-02-11)
|
18
|
+
|
19
|
+
[Full Changelog](https://github.com/keypup-io/cloudtasker/compare/v0.9.0...v0.9.1)
|
20
|
+
|
21
|
+
**Fixed bugs:**
|
22
|
+
- Cloud Task: raise `Cloudtasker::MaxTaskSizeExceededError` if job payload exceeds 100 KB. This is mainly to have production parity in development when running the local processing server.
|
23
|
+
|
24
|
+
## [v0.9.0](https://github.com/keypup-io/cloudtasker/tree/v0.9.0) (2020-01-23)
|
25
|
+
|
26
|
+
[Full Changelog](https://github.com/keypup-io/cloudtasker/compare/v0.8.2...v0.9.0)
|
27
|
+
|
28
|
+
**Fixed bugs:**
|
29
|
+
- Cloud Task: Base64 encode task body to support UTF-8 characters (e.g. emojis).
|
30
|
+
- Redis: Restrict to one connection (class level) to avoid too many DNS lookups
|
31
|
+
|
32
|
+
**Migration**
|
33
|
+
For Sinatra applications please update your Cloudtasker controller according to [this diff](https://github.com/keypup-io/cloudtasker/commit/311fa8f9beec91fbae012164a25b2ee6e261a2e4#diff-c2a0ea6c6e6c31c749d2e1acdc574f0f).
|
34
|
+
|
35
|
+
## [v0.8.2](https://github.com/keypup-io/cloudtasker/tree/v0.8.2) (2019-12-05)
|
36
|
+
|
37
|
+
[Full Changelog](https://github.com/keypup-io/cloudtasker/compare/v0.8.1...v0.8.2)
|
38
|
+
|
39
|
+
**Fixed bugs:**
|
40
|
+
- Config: do not add processor host to `Rails.application.config.hosts` if originally empty.
|
41
|
+
|
42
|
+
## [v0.8.1](https://github.com/keypup-io/cloudtasker/tree/v0.8.1) (2019-12-03)
|
43
|
+
|
44
|
+
[Full Changelog](https://github.com/keypup-io/cloudtasker/compare/v0.8.0...v0.8.1)
|
45
|
+
|
46
|
+
**Fixed bugs:**
|
47
|
+
- Local dev server: ensure job queue name is kept when taks is retried
|
48
|
+
- Rails/Controller: bypass Rails munge logic to preserve nil values inside job arguments.
|
49
|
+
|
3
50
|
## [v0.8.0](https://github.com/keypup-io/cloudtasker/tree/v0.8.0) (2019-11-27)
|
4
51
|
|
5
52
|
[Full Changelog](https://github.com/keypup-io/cloudtasker/compare/v0.7.0...v0.8.0)
|
data/README.md
CHANGED
@@ -635,7 +635,9 @@ If you enqueue this worker by omitting the second argument `MyWorker.perform_asy
|
|
635
635
|
- The `time_at` argument will be ignored by the `unique-job` extension, meaning that job uniqueness will be only based on the `user_id` argument.
|
636
636
|
|
637
637
|
### Handling big job payloads
|
638
|
-
|
638
|
+
Google Cloud Tasks enforces a limit of 100 KB for job payloads. Taking into accounts Cloudtasker authentication headers and meta information this leave ~85 KB of free space for JSONified job arguments.
|
639
|
+
|
640
|
+
Any excessive job payload (> 100 KB) will raise a `Cloudtasker::MaxTaskSizeExceededError`, both in production and development mode.
|
639
641
|
|
640
642
|
If you feel that a job payload is going to get big, prefer to store the payload using a datastore (e.g. Redis) and pass a reference to the job to retrieve the payload inside your job `perform` method.
|
641
643
|
|
@@ -16,9 +16,6 @@ module Cloudtasker
|
|
16
16
|
# Run a worker from a Cloud Task payload
|
17
17
|
#
|
18
18
|
def run
|
19
|
-
# Build payload
|
20
|
-
payload = JSON.parse(request.body.read).merge(job_retries: job_retries)
|
21
|
-
|
22
19
|
# Process payload
|
23
20
|
WorkerHandler.execute_from_payload!(payload)
|
24
21
|
head :no_content
|
@@ -37,6 +34,27 @@ module Cloudtasker
|
|
37
34
|
|
38
35
|
private
|
39
36
|
|
37
|
+
#
|
38
|
+
# Parse the request body and return the actual job
|
39
|
+
# payload.
|
40
|
+
#
|
41
|
+
# @return [Hash] The job payload
|
42
|
+
#
|
43
|
+
def payload
|
44
|
+
@payload ||= begin
|
45
|
+
# Get raw body
|
46
|
+
content = request.body.read
|
47
|
+
|
48
|
+
# Decode content if the body is Base64 encoded
|
49
|
+
if request.headers[Cloudtasker::Config::ENCODING_HEADER].to_s.downcase == 'base64'
|
50
|
+
content = Base64.decode64(content)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Return content parsed as JSON and add job retries count
|
54
|
+
JSON.parse(content).merge(job_retries: job_retries)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
40
58
|
#
|
41
59
|
# Extract the number of times this task failed at runtime.
|
42
60
|
#
|
data/cloudtasker.gemspec
CHANGED
@@ -32,17 +32,17 @@ Gem::Specification.new do |spec|
|
|
32
32
|
|
33
33
|
spec.add_dependency 'activesupport'
|
34
34
|
spec.add_dependency 'fugit'
|
35
|
-
spec.add_dependency 'google-cloud-tasks'
|
35
|
+
spec.add_dependency 'google-cloud-tasks', '~> 1.0'
|
36
36
|
spec.add_dependency 'jwt'
|
37
37
|
spec.add_dependency 'redis'
|
38
38
|
|
39
39
|
spec.add_development_dependency 'appraisal'
|
40
40
|
spec.add_development_dependency 'bundler', '~> 2.0'
|
41
41
|
spec.add_development_dependency 'github_changelog_generator'
|
42
|
-
spec.add_development_dependency 'rake', '
|
42
|
+
spec.add_development_dependency 'rake', '>= 12.3.3'
|
43
43
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
44
44
|
spec.add_development_dependency 'rubocop', '0.76.0'
|
45
|
-
spec.add_development_dependency 'rubocop-rspec'
|
45
|
+
spec.add_development_dependency 'rubocop-rspec', '1.37.0'
|
46
46
|
spec.add_development_dependency 'timecop'
|
47
47
|
spec.add_development_dependency 'webmock'
|
48
48
|
|
data/lib/cloudtasker.rb
CHANGED
@@ -8,6 +8,7 @@ require 'cloudtasker/config'
|
|
8
8
|
require 'cloudtasker/authentication_error'
|
9
9
|
require 'cloudtasker/dead_worker_error'
|
10
10
|
require 'cloudtasker/invalid_worker_error'
|
11
|
+
require 'cloudtasker/max_task_size_exceeded_error'
|
11
12
|
|
12
13
|
require 'cloudtasker/middleware/chain'
|
13
14
|
require 'cloudtasker/authenticator'
|
@@ -82,6 +82,29 @@ module Cloudtasker
|
|
82
82
|
Google::Protobuf::Timestamp.new.tap { |e| e.seconds = schedule_time.to_i }
|
83
83
|
end
|
84
84
|
|
85
|
+
#
|
86
|
+
# Format the job payload sent to Cloud Tasks.
|
87
|
+
#
|
88
|
+
# @param [Hash] hash The worker payload.
|
89
|
+
#
|
90
|
+
# @return [Hash] The Cloud Task payloadd.
|
91
|
+
#
|
92
|
+
def self.format_task_payload(payload)
|
93
|
+
payload = JSON.parse(payload.to_json, symbolize_names: true) # deep dup
|
94
|
+
|
95
|
+
# Format schedule time to Google Protobuf timestamp
|
96
|
+
payload[:schedule_time] = format_schedule_time(payload[:schedule_time])
|
97
|
+
|
98
|
+
# Encode job content to support UTF-8. Google Cloud Task
|
99
|
+
# expect content to be ASCII-8BIT compatible (binary)
|
100
|
+
payload[:http_request][:headers] ||= {}
|
101
|
+
payload[:http_request][:headers][Cloudtasker::Config::CONTENT_TYPE_HEADER] = 'text/json'
|
102
|
+
payload[:http_request][:headers][Cloudtasker::Config::ENCODING_HEADER] = 'Base64'
|
103
|
+
payload[:http_request][:body] = Base64.encode64(payload[:http_request][:body])
|
104
|
+
|
105
|
+
payload
|
106
|
+
end
|
107
|
+
|
85
108
|
#
|
86
109
|
# Find a task by id.
|
87
110
|
#
|
@@ -104,10 +127,7 @@ module Cloudtasker
|
|
104
127
|
# @return [Cloudtasker::Backend::GoogleCloudTask, nil] The created task.
|
105
128
|
#
|
106
129
|
def self.create(payload)
|
107
|
-
|
108
|
-
payload = payload.merge(
|
109
|
-
schedule_time: format_schedule_time(payload[:schedule_time])
|
110
|
-
).compact
|
130
|
+
payload = format_task_payload(payload)
|
111
131
|
|
112
132
|
# Extract relative queue name
|
113
133
|
relative_queue = payload.delete(:queue)
|
@@ -126,7 +146,7 @@ module Cloudtasker
|
|
126
146
|
#
|
127
147
|
def self.delete(id)
|
128
148
|
client.delete_task(id)
|
129
|
-
rescue Google::Gax::RetryError
|
149
|
+
rescue Google::Gax::RetryError, GRPC::NotFound
|
130
150
|
nil
|
131
151
|
end
|
132
152
|
|
@@ -48,6 +48,8 @@ module Cloudtasker
|
|
48
48
|
# @return [Cloudtasker::CloudTask] The created task.
|
49
49
|
#
|
50
50
|
def self.create(payload)
|
51
|
+
raise MaxTaskSizeExceededError if payload.to_json.bytesize > Config::MAX_TASK_SIZE
|
52
|
+
|
51
53
|
resp = backend.create(payload)&.to_h
|
52
54
|
resp ? new(resp) : nil
|
53
55
|
end
|
data/lib/cloudtasker/config.rb
CHANGED
@@ -9,9 +9,21 @@ module Cloudtasker
|
|
9
9
|
attr_writer :secret, :gcp_location_id, :gcp_project_id,
|
10
10
|
:gcp_queue_prefix, :processor_path, :logger, :mode, :max_retries
|
11
11
|
|
12
|
+
# Max Cloud Task size in bytes
|
13
|
+
MAX_TASK_SIZE = 100 * 1024 # 100 KB
|
14
|
+
|
12
15
|
# Retry header in Cloud Task responses
|
13
16
|
RETRY_HEADER = 'X-CloudTasks-TaskExecutionCount'
|
14
17
|
|
18
|
+
# Content-Transfer-Encoding header in Cloud Task responses
|
19
|
+
ENCODING_HEADER = 'Content-Transfer-Encoding'
|
20
|
+
|
21
|
+
# Content Type
|
22
|
+
CONTENT_TYPE_HEADER = 'Content-Type'
|
23
|
+
|
24
|
+
# Authorization header
|
25
|
+
AUTHORIZATION_HEADER = 'Authorization'
|
26
|
+
|
15
27
|
# Default values
|
16
28
|
DEFAULT_LOCATION_ID = 'us-east1'
|
17
29
|
DEFAULT_PROCESSOR_PATH = '/cloudtasker/run'
|
@@ -102,7 +114,10 @@ module Cloudtasker
|
|
102
114
|
@processor_host = val
|
103
115
|
|
104
116
|
# Check if Rails supports host filtering
|
105
|
-
return unless val &&
|
117
|
+
return unless val &&
|
118
|
+
defined?(Rails) &&
|
119
|
+
Rails.application.config.respond_to?(:hosts) &&
|
120
|
+
Rails.application.config.hosts&.any?
|
106
121
|
|
107
122
|
# Add processor host to the list of authorized hosts
|
108
123
|
Rails.application.config.hosts << val.gsub(%r{https?://}, '')
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cloudtasker
|
4
|
+
# Handle Cloud Task size quota
|
5
|
+
# See: https://cloud.google.com/appengine/quotas#Task_Queue
|
6
|
+
#
|
7
|
+
class MaxTaskSizeExceededError < StandardError
|
8
|
+
MSG = 'The size of Cloud Tasks must not exceed 100KB'
|
9
|
+
|
10
|
+
def initialize(msg = MSG)
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -8,13 +8,17 @@ module Cloudtasker
|
|
8
8
|
# Suffix added to cache keys when locking them
|
9
9
|
LOCK_KEY_PREFIX = 'cloudtasker/lock'
|
10
10
|
|
11
|
+
def self.client
|
12
|
+
@client ||= Redis.new(Cloudtasker.config.redis || {})
|
13
|
+
end
|
14
|
+
|
11
15
|
#
|
12
16
|
# Return the underlying redis client.
|
13
17
|
#
|
14
18
|
# @return [Redis] The redis client.
|
15
19
|
#
|
16
20
|
def client
|
17
|
-
@client ||=
|
21
|
+
@client ||= self.class.client
|
18
22
|
end
|
19
23
|
|
20
24
|
#
|
data/lib/cloudtasker/version.rb
CHANGED
@@ -42,8 +42,8 @@ module Cloudtasker
|
|
42
42
|
http_method: 'POST',
|
43
43
|
url: Cloudtasker.config.processor_url,
|
44
44
|
headers: {
|
45
|
-
|
46
|
-
|
45
|
+
Cloudtasker::Config::CONTENT_TYPE_HEADER => 'application/json',
|
46
|
+
Cloudtasker::Config::AUTHORIZATION_HEADER => "Bearer #{Authenticator.verification_token}"
|
47
47
|
},
|
48
48
|
body: worker_payload.to_json
|
49
49
|
},
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloudtasker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Arnaud Lachaume
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -42,16 +42,16 @@ dependencies:
|
|
42
42
|
name: google-cloud-tasks
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
47
|
+
version: '1.0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
54
|
+
version: '1.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: jwt
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -126,16 +126,16 @@ dependencies:
|
|
126
126
|
name: rake
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
|
-
- - "
|
129
|
+
- - ">="
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version:
|
131
|
+
version: 12.3.3
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
|
-
- - "
|
136
|
+
- - ">="
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version:
|
138
|
+
version: 12.3.3
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: rspec
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -168,16 +168,16 @@ dependencies:
|
|
168
168
|
name: rubocop-rspec
|
169
169
|
requirement: !ruby/object:Gem::Requirement
|
170
170
|
requirements:
|
171
|
-
- -
|
171
|
+
- - '='
|
172
172
|
- !ruby/object:Gem::Version
|
173
|
-
version:
|
173
|
+
version: 1.37.0
|
174
174
|
type: :development
|
175
175
|
prerelease: false
|
176
176
|
version_requirements: !ruby/object:Gem::Requirement
|
177
177
|
requirements:
|
178
|
-
- -
|
178
|
+
- - '='
|
179
179
|
- !ruby/object:Gem::Version
|
180
|
-
version:
|
180
|
+
version: 1.37.0
|
181
181
|
- !ruby/object:Gem::Dependency
|
182
182
|
name: timecop
|
183
183
|
requirement: !ruby/object:Gem::Requirement
|
@@ -256,10 +256,10 @@ executables:
|
|
256
256
|
extensions: []
|
257
257
|
extra_rdoc_files: []
|
258
258
|
files:
|
259
|
+
- ".github/workflows/test.yml"
|
259
260
|
- ".gitignore"
|
260
261
|
- ".rspec"
|
261
262
|
- ".rubocop.yml"
|
262
|
-
- ".travis.yml"
|
263
263
|
- Appraisals
|
264
264
|
- CHANGELOG.md
|
265
265
|
- CODE_OF_CONDUCT.md
|
@@ -320,6 +320,7 @@ files:
|
|
320
320
|
- lib/cloudtasker/engine.rb
|
321
321
|
- lib/cloudtasker/invalid_worker_error.rb
|
322
322
|
- lib/cloudtasker/local_server.rb
|
323
|
+
- lib/cloudtasker/max_task_size_exceeded_error.rb
|
323
324
|
- lib/cloudtasker/meta_store.rb
|
324
325
|
- lib/cloudtasker/middleware/chain.rb
|
325
326
|
- lib/cloudtasker/redis_client.rb
|
@@ -367,8 +368,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
367
368
|
- !ruby/object:Gem::Version
|
368
369
|
version: '0'
|
369
370
|
requirements: []
|
370
|
-
|
371
|
-
rubygems_version: 2.7.9
|
371
|
+
rubygems_version: 3.0.0
|
372
372
|
signing_key:
|
373
373
|
specification_version: 4
|
374
374
|
summary: Background jobs for Ruby using Google Cloud Tasks (beta)
|
data/.travis.yml
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
---
|
2
|
-
language: ruby
|
3
|
-
cache: bundler
|
4
|
-
rvm:
|
5
|
-
- 2.5.5
|
6
|
-
services:
|
7
|
-
- redis-server
|
8
|
-
before_install: gem install bundler -v 2.0.2
|
9
|
-
before_script: bundle exec rubocop
|
10
|
-
gemfile:
|
11
|
-
- gemfiles/google_cloud_tasks_1.0.gemfile
|
12
|
-
- gemfiles/google_cloud_tasks_1.1.gemfile
|
13
|
-
- gemfiles/google_cloud_tasks_1.2.gemfile
|
14
|
-
- gemfiles/google_cloud_tasks_1.3.gemfile
|
15
|
-
- gemfiles/rails_5.2.gemfile
|
16
|
-
- gemfiles/rails_6.0.gemfile
|