my_api_client 0.14.0.pre → 0.14.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.
- checksums.yaml +4 -4
- data/.circleci/config.yml +90 -35
- data/.envrc.skeleton +1 -0
- data/.rubocop.yml +5 -1
- data/.rubocop_todo.yml +1 -1
- data/CHANGELOG.md +10 -1
- data/Gemfile.lock +6 -6
- data/example/api_clients/application_api_client.rb +21 -0
- data/example/api_clients/my_error_api_client.rb +34 -0
- data/example/api_clients/my_errors.rb +27 -0
- data/example/api_clients/my_rest_api_client.rb +42 -0
- data/example/api_clients/my_status_api_client.rb +22 -0
- data/lib/my_api_client/rspec/matchers/request_to.rb +3 -4
- data/lib/my_api_client/version.rb +1 -1
- data/my_api/.envrc.skeleton +3 -0
- data/my_api/.gitignore +14 -0
- data/my_api/.jetskeep +1 -0
- data/my_api/.rspec +3 -0
- data/my_api/.ruby-version +1 -0
- data/my_api/Gemfile +23 -0
- data/my_api/Gemfile.lock +243 -0
- data/my_api/Procfile +7 -0
- data/my_api/README.md +48 -0
- data/my_api/Rakefile +4 -0
- data/my_api/app/controllers/application_controller.rb +5 -0
- data/my_api/app/controllers/error_controller.rb +21 -0
- data/my_api/app/controllers/rest_controller.rb +60 -0
- data/my_api/app/controllers/status_controller.rb +11 -0
- data/my_api/app/helpers/application_helper.rb +5 -0
- data/my_api/app/jobs/application_job.rb +7 -0
- data/my_api/app/models/application_item.rb +5 -0
- data/my_api/config.ru +7 -0
- data/my_api/config/application.rb +73 -0
- data/my_api/config/dynamodb.yml +22 -0
- data/my_api/config/environments/development.rb +9 -0
- data/my_api/config/environments/production.rb +11 -0
- data/my_api/config/environments/test.rb +9 -0
- data/my_api/config/routes.rb +16 -0
- data/my_api/db/.gitkeep +0 -0
- data/my_api/public/404.html +67 -0
- data/my_api/public/422.html +67 -0
- data/my_api/public/500.html +66 -0
- data/my_api/public/favicon.ico +0 -0
- data/my_api/public/index.html +91 -0
- data/my_api/spec/controllers/error_controller_spec.rb +43 -0
- data/my_api/spec/controllers/rest_controller_spec.rb +81 -0
- data/my_api/spec/controllers/status_controller_spec.rb +47 -0
- data/my_api/spec/fixtures/payloads/posts-index.json +51 -0
- data/my_api/spec/fixtures/payloads/posts-show.json +53 -0
- data/my_api/spec/spec_helper.rb +26 -0
- metadata +45 -4
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module MyErrors
|
4
|
+
# 400 Bad Request
|
5
|
+
class BadRequest < MyApiClient::ClientError; end
|
6
|
+
|
7
|
+
# 401 Unauthorized
|
8
|
+
class Unauthorized < MyApiClient::ClientError; end
|
9
|
+
|
10
|
+
# 403 Forbidden
|
11
|
+
class Forbidden < MyApiClient::ClientError; end
|
12
|
+
|
13
|
+
# Error code: 0
|
14
|
+
class ErrorCode00 < MyApiClient::ClientError; end
|
15
|
+
|
16
|
+
# Error code: 10
|
17
|
+
class ErrorCode10 < MyApiClient::ClientError; end
|
18
|
+
|
19
|
+
# Error code: 20 to 29
|
20
|
+
class ErrorCode2x < MyApiClient::ClientError; end
|
21
|
+
|
22
|
+
# Error code: 30
|
23
|
+
class ErrorCode30 < MyApiClient::ClientError; end
|
24
|
+
|
25
|
+
# Error code: other
|
26
|
+
class ErrorCodeOther < MyApiClient::ClientError; end
|
27
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'application_api_client'
|
4
|
+
|
5
|
+
# An usage example of the `my_api_client`.
|
6
|
+
# See also: my_api/app/controllers/rest_controller.rb
|
7
|
+
class MyRestApiClient < ApplicationApiClient
|
8
|
+
# GET rest
|
9
|
+
def get_posts(order: :asc)
|
10
|
+
order = :desc unless order == :asc
|
11
|
+
query = { order: order }
|
12
|
+
get 'rest', query: query, headers: headers
|
13
|
+
end
|
14
|
+
|
15
|
+
# GET rest/:id
|
16
|
+
def get_post(id:)
|
17
|
+
get "rest/#{id}", headers: headers
|
18
|
+
end
|
19
|
+
|
20
|
+
# POST rest
|
21
|
+
def create_post(title:)
|
22
|
+
body = { title: title }
|
23
|
+
post 'rest', body: body, headers: headers
|
24
|
+
end
|
25
|
+
|
26
|
+
# POST/PUT/PATCH rest/:id
|
27
|
+
def update_post(id:, title:)
|
28
|
+
body = { title: title }
|
29
|
+
patch "rest/#{id}", body: body, headers: headers
|
30
|
+
end
|
31
|
+
|
32
|
+
# DELETE rest/:id
|
33
|
+
def delete_post(id:)
|
34
|
+
delete "rest/#{id}", headers: headers
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def headers
|
40
|
+
{ 'Content-Type': 'application/json;charset=UTF-8' }
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'application_api_client'
|
4
|
+
|
5
|
+
# An usage example of the `my_api_client`.
|
6
|
+
# See also: my_api/app/controllers/status_controller.rb
|
7
|
+
class MyStatusApiClient < ApplicationApiClient
|
8
|
+
error_handling status_code: 400, raise: MyErrors::BadRequest
|
9
|
+
error_handling status_code: 401, raise: MyErrors::Unauthorized
|
10
|
+
error_handling status_code: 403, raise: MyErrors::Forbidden
|
11
|
+
|
12
|
+
# GET status/:status
|
13
|
+
def get_status(status:)
|
14
|
+
get "status/#{status}", headers: headers
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def headers
|
20
|
+
{ 'Content-Type': 'application/json;charset=UTF-8' }
|
21
|
+
end
|
22
|
+
end
|
@@ -8,10 +8,9 @@ RSpec::Matchers.define :request_to do |expected_method, expected_url|
|
|
8
8
|
match do |api_request|
|
9
9
|
disable_logging
|
10
10
|
@expected = {
|
11
|
-
request_line: request_line(expected_method, expected_url),
|
11
|
+
request_line: request_line(expected_method, expected_url, expected_options[:query]),
|
12
12
|
body: expected_options[:body],
|
13
13
|
headers: expected_options[:headers],
|
14
|
-
query: expected_options[:query],
|
15
14
|
}.compact
|
16
15
|
@actual = {}
|
17
16
|
sawyer = instance_double(Sawyer::Agent)
|
@@ -24,7 +23,6 @@ RSpec::Matchers.define :request_to do |expected_method, expected_url|
|
|
24
23
|
request_line: request_line(method, @actual_schema_and_hostname + pathname),
|
25
24
|
body: body,
|
26
25
|
headers: options[:headers],
|
27
|
-
query: options[:query],
|
28
26
|
}.compact
|
29
27
|
end.and_return(dummy_response)
|
30
28
|
safe_execution(api_request)
|
@@ -51,7 +49,8 @@ RSpec::Matchers.define :request_to do |expected_method, expected_url|
|
|
51
49
|
nil
|
52
50
|
end
|
53
51
|
|
54
|
-
def request_line(method, url)
|
52
|
+
def request_line(method, url, query = nil)
|
53
|
+
url += '?' + query.to_query if query.present?
|
55
54
|
"#{method.upcase} #{url}"
|
56
55
|
end
|
57
56
|
|
data/my_api/.gitignore
ADDED
data/my_api/.jetskeep
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
pack
|
data/my_api/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.7.0
|
data/my_api/Gemfile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source 'https://rubygems.org'
|
4
|
+
|
5
|
+
gem 'jets'
|
6
|
+
|
7
|
+
gem 'dynomite'
|
8
|
+
|
9
|
+
# development and test groups are not bundled as part of the deployment
|
10
|
+
group :development, :test do
|
11
|
+
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
|
12
|
+
gem 'byebug', platforms: %i[mri mingw x64_mingw]
|
13
|
+
gem 'puma'
|
14
|
+
gem 'rack'
|
15
|
+
gem 'shotgun'
|
16
|
+
end
|
17
|
+
|
18
|
+
group :test do
|
19
|
+
gem 'capybara'
|
20
|
+
gem 'launchy'
|
21
|
+
gem 'rspec'
|
22
|
+
gem 'rspec_junit_formatter'
|
23
|
+
end
|
data/my_api/Gemfile.lock
ADDED
@@ -0,0 +1,243 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
actionmailer (6.0.2.1)
|
5
|
+
actionpack (= 6.0.2.1)
|
6
|
+
actionview (= 6.0.2.1)
|
7
|
+
activejob (= 6.0.2.1)
|
8
|
+
mail (~> 2.5, >= 2.5.4)
|
9
|
+
rails-dom-testing (~> 2.0)
|
10
|
+
actionpack (6.0.2.1)
|
11
|
+
actionview (= 6.0.2.1)
|
12
|
+
activesupport (= 6.0.2.1)
|
13
|
+
rack (~> 2.0, >= 2.0.8)
|
14
|
+
rack-test (>= 0.6.3)
|
15
|
+
rails-dom-testing (~> 2.0)
|
16
|
+
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
17
|
+
actionview (6.0.2.1)
|
18
|
+
activesupport (= 6.0.2.1)
|
19
|
+
builder (~> 3.1)
|
20
|
+
erubi (~> 1.4)
|
21
|
+
rails-dom-testing (~> 2.0)
|
22
|
+
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
23
|
+
activejob (6.0.2.1)
|
24
|
+
activesupport (= 6.0.2.1)
|
25
|
+
globalid (>= 0.3.6)
|
26
|
+
activemodel (6.0.2.1)
|
27
|
+
activesupport (= 6.0.2.1)
|
28
|
+
activerecord (6.0.2.1)
|
29
|
+
activemodel (= 6.0.2.1)
|
30
|
+
activesupport (= 6.0.2.1)
|
31
|
+
activesupport (6.0.2.1)
|
32
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
33
|
+
i18n (>= 0.7, < 2)
|
34
|
+
minitest (~> 5.1)
|
35
|
+
tzinfo (~> 1.1)
|
36
|
+
zeitwerk (~> 2.2)
|
37
|
+
addressable (2.7.0)
|
38
|
+
public_suffix (>= 2.0.2, < 5.0)
|
39
|
+
aws-eventstream (1.0.3)
|
40
|
+
aws-mfa-secure (0.4.0)
|
41
|
+
activesupport
|
42
|
+
aws-sdk-core
|
43
|
+
aws_config
|
44
|
+
memoist
|
45
|
+
rainbow
|
46
|
+
thor
|
47
|
+
zeitwerk
|
48
|
+
aws-partitions (1.278.0)
|
49
|
+
aws-sdk-apigateway (1.36.0)
|
50
|
+
aws-sdk-core (~> 3, >= 3.71.0)
|
51
|
+
aws-sigv4 (~> 1.1)
|
52
|
+
aws-sdk-cloudformation (1.30.0)
|
53
|
+
aws-sdk-core (~> 3, >= 3.71.0)
|
54
|
+
aws-sigv4 (~> 1.1)
|
55
|
+
aws-sdk-cloudwatchlogs (1.28.0)
|
56
|
+
aws-sdk-core (~> 3, >= 3.71.0)
|
57
|
+
aws-sigv4 (~> 1.1)
|
58
|
+
aws-sdk-core (3.90.1)
|
59
|
+
aws-eventstream (~> 1.0, >= 1.0.2)
|
60
|
+
aws-partitions (~> 1, >= 1.239.0)
|
61
|
+
aws-sigv4 (~> 1.1)
|
62
|
+
jmespath (~> 1.0)
|
63
|
+
aws-sdk-dynamodb (1.43.0)
|
64
|
+
aws-sdk-core (~> 3, >= 3.71.0)
|
65
|
+
aws-sigv4 (~> 1.1)
|
66
|
+
aws-sdk-kinesis (1.20.0)
|
67
|
+
aws-sdk-core (~> 3, >= 3.71.0)
|
68
|
+
aws-sigv4 (~> 1.1)
|
69
|
+
aws-sdk-kms (1.29.0)
|
70
|
+
aws-sdk-core (~> 3, >= 3.71.0)
|
71
|
+
aws-sigv4 (~> 1.1)
|
72
|
+
aws-sdk-lambda (1.36.0)
|
73
|
+
aws-sdk-core (~> 3, >= 3.71.0)
|
74
|
+
aws-sigv4 (~> 1.1)
|
75
|
+
aws-sdk-s3 (1.60.2)
|
76
|
+
aws-sdk-core (~> 3, >= 3.83.0)
|
77
|
+
aws-sdk-kms (~> 1)
|
78
|
+
aws-sigv4 (~> 1.1)
|
79
|
+
aws-sdk-sns (1.21.0)
|
80
|
+
aws-sdk-core (~> 3, >= 3.71.0)
|
81
|
+
aws-sigv4 (~> 1.1)
|
82
|
+
aws-sdk-sqs (1.23.1)
|
83
|
+
aws-sdk-core (~> 3, >= 3.71.0)
|
84
|
+
aws-sigv4 (~> 1.1)
|
85
|
+
aws-sdk-ssm (1.71.0)
|
86
|
+
aws-sdk-core (~> 3, >= 3.71.0)
|
87
|
+
aws-sigv4 (~> 1.1)
|
88
|
+
aws-sigv4 (1.1.1)
|
89
|
+
aws-eventstream (~> 1.0, >= 1.0.2)
|
90
|
+
aws_config (0.1.0)
|
91
|
+
builder (3.2.4)
|
92
|
+
byebug (11.1.1)
|
93
|
+
capybara (3.31.0)
|
94
|
+
addressable
|
95
|
+
mini_mime (>= 0.1.3)
|
96
|
+
nokogiri (~> 1.8)
|
97
|
+
rack (>= 1.6.0)
|
98
|
+
rack-test (>= 0.6.3)
|
99
|
+
regexp_parser (~> 1.5)
|
100
|
+
xpath (~> 3.2)
|
101
|
+
cfn_camelizer (0.4.9)
|
102
|
+
activesupport
|
103
|
+
memoist
|
104
|
+
rainbow
|
105
|
+
cfnresponse (0.4.0)
|
106
|
+
concurrent-ruby (1.1.6)
|
107
|
+
crass (1.0.6)
|
108
|
+
diff-lcs (1.3)
|
109
|
+
dotenv (2.7.5)
|
110
|
+
dynomite (1.2.5)
|
111
|
+
activesupport
|
112
|
+
aws-sdk-dynamodb
|
113
|
+
rainbow
|
114
|
+
erubi (1.9.0)
|
115
|
+
gems (1.2.0)
|
116
|
+
globalid (0.4.2)
|
117
|
+
activesupport (>= 4.2.0)
|
118
|
+
hashie (4.1.0)
|
119
|
+
i18n (1.8.2)
|
120
|
+
concurrent-ruby (~> 1.0)
|
121
|
+
jets (2.3.13)
|
122
|
+
actionmailer (~> 6.0.0)
|
123
|
+
actionpack (~> 6.0.0)
|
124
|
+
actionview (~> 6.0.0)
|
125
|
+
activerecord (~> 6.0.0)
|
126
|
+
activesupport (~> 6.0.0)
|
127
|
+
aws-mfa-secure (~> 0.4.0)
|
128
|
+
aws-sdk-apigateway
|
129
|
+
aws-sdk-cloudformation
|
130
|
+
aws-sdk-cloudwatchlogs
|
131
|
+
aws-sdk-dynamodb
|
132
|
+
aws-sdk-kinesis
|
133
|
+
aws-sdk-lambda
|
134
|
+
aws-sdk-s3
|
135
|
+
aws-sdk-sns
|
136
|
+
aws-sdk-sqs
|
137
|
+
aws-sdk-ssm
|
138
|
+
cfn_camelizer (~> 0.4.6)
|
139
|
+
cfnresponse
|
140
|
+
dotenv
|
141
|
+
gems
|
142
|
+
hashie
|
143
|
+
jets-gems
|
144
|
+
jets-html-sanitizer
|
145
|
+
json
|
146
|
+
kramdown
|
147
|
+
memoist
|
148
|
+
mimemagic
|
149
|
+
rack
|
150
|
+
railties (~> 6.0.0)
|
151
|
+
rainbow
|
152
|
+
recursive-open-struct
|
153
|
+
shotgun
|
154
|
+
text-table
|
155
|
+
thor
|
156
|
+
zeitwerk
|
157
|
+
jets-gems (0.2.0)
|
158
|
+
gems
|
159
|
+
jets-html-sanitizer (1.0.4)
|
160
|
+
loofah (~> 2.2, >= 2.2.2)
|
161
|
+
jmespath (1.4.0)
|
162
|
+
json (2.3.0)
|
163
|
+
kramdown (2.1.0)
|
164
|
+
launchy (2.5.0)
|
165
|
+
addressable (~> 2.7)
|
166
|
+
loofah (2.4.0)
|
167
|
+
crass (~> 1.0.2)
|
168
|
+
nokogiri (>= 1.5.9)
|
169
|
+
mail (2.7.1)
|
170
|
+
mini_mime (>= 0.1.1)
|
171
|
+
memoist (0.16.2)
|
172
|
+
method_source (0.9.2)
|
173
|
+
mimemagic (0.3.4)
|
174
|
+
mini_mime (1.0.2)
|
175
|
+
mini_portile2 (2.4.0)
|
176
|
+
minitest (5.14.0)
|
177
|
+
nio4r (2.5.2)
|
178
|
+
nokogiri (1.10.8)
|
179
|
+
mini_portile2 (~> 2.4.0)
|
180
|
+
public_suffix (4.0.3)
|
181
|
+
puma (4.3.3)
|
182
|
+
nio4r (~> 2.0)
|
183
|
+
rack (2.2.2)
|
184
|
+
rack-test (1.1.0)
|
185
|
+
rack (>= 1.0, < 3)
|
186
|
+
rails-dom-testing (2.0.3)
|
187
|
+
activesupport (>= 4.2.0)
|
188
|
+
nokogiri (>= 1.6)
|
189
|
+
rails-html-sanitizer (1.3.0)
|
190
|
+
loofah (~> 2.3)
|
191
|
+
railties (6.0.2.1)
|
192
|
+
actionpack (= 6.0.2.1)
|
193
|
+
activesupport (= 6.0.2.1)
|
194
|
+
method_source
|
195
|
+
rake (>= 0.8.7)
|
196
|
+
thor (>= 0.20.3, < 2.0)
|
197
|
+
rainbow (3.0.0)
|
198
|
+
rake (13.0.1)
|
199
|
+
recursive-open-struct (1.1.0)
|
200
|
+
regexp_parser (1.7.0)
|
201
|
+
rspec (3.9.0)
|
202
|
+
rspec-core (~> 3.9.0)
|
203
|
+
rspec-expectations (~> 3.9.0)
|
204
|
+
rspec-mocks (~> 3.9.0)
|
205
|
+
rspec-core (3.9.1)
|
206
|
+
rspec-support (~> 3.9.1)
|
207
|
+
rspec-expectations (3.9.0)
|
208
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
209
|
+
rspec-support (~> 3.9.0)
|
210
|
+
rspec-mocks (3.9.1)
|
211
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
212
|
+
rspec-support (~> 3.9.0)
|
213
|
+
rspec-support (3.9.2)
|
214
|
+
rspec_junit_formatter (0.4.1)
|
215
|
+
rspec-core (>= 2, < 4, != 2.12.0)
|
216
|
+
shotgun (0.9.2)
|
217
|
+
rack (>= 1.0)
|
218
|
+
text-table (1.2.4)
|
219
|
+
thor (1.0.1)
|
220
|
+
thread_safe (0.3.6)
|
221
|
+
tzinfo (1.2.6)
|
222
|
+
thread_safe (~> 0.1)
|
223
|
+
xpath (3.2.0)
|
224
|
+
nokogiri (~> 1.8)
|
225
|
+
zeitwerk (2.2.2)
|
226
|
+
|
227
|
+
PLATFORMS
|
228
|
+
ruby
|
229
|
+
|
230
|
+
DEPENDENCIES
|
231
|
+
byebug
|
232
|
+
capybara
|
233
|
+
dynomite
|
234
|
+
jets
|
235
|
+
launchy
|
236
|
+
puma
|
237
|
+
rack
|
238
|
+
rspec
|
239
|
+
rspec_junit_formatter
|
240
|
+
shotgun
|
241
|
+
|
242
|
+
BUNDLED WITH
|
243
|
+
2.1.4
|
data/my_api/Procfile
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
local: dynamodb-local # port 8000
|
2
|
+
admin: env AWS_ACCESS_KEY_ID=$DYNAMODB_ADMIN_AWS_ACCESS_KEY_ID PORT=8001 dynamodb-admin # port 8001
|
3
|
+
# web: jets server # port 8888
|
4
|
+
|
5
|
+
# Using Procfile to just start local dynamodb services for now.
|
6
|
+
# To start jets server for now use:
|
7
|
+
# jets server
|
data/my_api/README.md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# My API
|
2
|
+
|
3
|
+
This is the real API for integration testing with `my_api_client`.
|
4
|
+
|
5
|
+
It's built by [Ruby on Jets](https://rubyonjets.com/).
|
6
|
+
|
7
|
+
## APIs
|
8
|
+
|
9
|
+
### My Rest API
|
10
|
+
|
11
|
+
This is a simple REST API that returns a specified response.
|
12
|
+
|
13
|
+
* `GET rest`
|
14
|
+
* `GET rest/:id`
|
15
|
+
* `POST rest`
|
16
|
+
* `POST/PUT/PATCH rest/:id`
|
17
|
+
* `DELETE rest/:id`
|
18
|
+
|
19
|
+
### My Status API
|
20
|
+
|
21
|
+
This API returns arbitrary status code.
|
22
|
+
|
23
|
+
* `GET status/:status`
|
24
|
+
|
25
|
+
### My Error API
|
26
|
+
|
27
|
+
This API returns arbitrary error code as JSON.
|
28
|
+
|
29
|
+
* `GET error/:code`
|
30
|
+
|
31
|
+
## Deployment
|
32
|
+
|
33
|
+
You need to prepare following environment variables:
|
34
|
+
|
35
|
+
* `AWS_REGION`
|
36
|
+
* `AWS_ACCESS_KEY_ID`
|
37
|
+
* `AWS_SECRET_ACCESS_KEY`
|
38
|
+
|
39
|
+
For information on how to create an AWS access key and secret, see the following site:
|
40
|
+
|
41
|
+
:link: [Minimal Deploy IAM Policy \- Jets Ruby Serverless Framework](https://rubyonjets.com/docs/extras/minimal-deploy-iam/)
|
42
|
+
|
43
|
+
|
44
|
+
And execute following command:
|
45
|
+
|
46
|
+
```sh
|
47
|
+
$ bundle exec jets deploy
|
48
|
+
```
|