dpl 1.8.48.travis.2486.5 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +2 -0
  3. data/.travis.yml +42 -21
  4. data/Gemfile +3 -98
  5. data/README.md +5 -16
  6. data/Rakefile +160 -1
  7. data/dpl-anynines.gemspec +3 -0
  8. data/dpl-atlas.gemspec +3 -0
  9. data/dpl-azure_webapps.gemspec +3 -0
  10. data/dpl-bintray.gemspec +3 -0
  11. data/dpl-bitballoon.gemspec +3 -0
  12. data/dpl-bluemix_cloud_foundry.gemspec +3 -0
  13. data/dpl-boxfuse.gemspec +3 -0
  14. data/dpl-catalyze.gemspec +3 -0
  15. data/dpl-chef_supermarket.gemspec +8 -0
  16. data/dpl-cloud66.gemspec +3 -0
  17. data/dpl-cloud_files.gemspec +3 -0
  18. data/dpl-cloud_foundry.gemspec +3 -0
  19. data/dpl-code_deploy.gemspec +3 -0
  20. data/dpl-deis.gemspec +3 -0
  21. data/dpl-divshot.gemspec +3 -0
  22. data/dpl-elastic_beanstalk.gemspec +3 -0
  23. data/dpl-engine_yard.gemspec +3 -0
  24. data/dpl-firebase.gemspec +3 -0
  25. data/dpl-gae.gemspec +3 -0
  26. data/dpl-gcs.gemspec +3 -0
  27. data/dpl-hackage.gemspec +3 -0
  28. data/dpl-heroku.gemspec +3 -0
  29. data/dpl-lambda.gemspec +3 -0
  30. data/dpl-launchpad.gemspec +3 -0
  31. data/dpl-modulus.gemspec +3 -0
  32. data/dpl-npm.gemspec +3 -0
  33. data/dpl-openshift.gemspec +3 -0
  34. data/dpl-ops_works.gemspec +3 -0
  35. data/dpl-packagecloud.gemspec +3 -0
  36. data/dpl-pages.gemspec +3 -0
  37. data/dpl-puppet_forge.gemspec +3 -0
  38. data/dpl-pypi.gemspec +3 -0
  39. data/dpl-releases.gemspec +3 -0
  40. data/dpl-rubygems.gemspec +3 -0
  41. data/dpl-s3.gemspec +3 -0
  42. data/dpl-scalingo.gemspec +3 -0
  43. data/dpl-script.gemspec +3 -0
  44. data/dpl-surge.gemspec +3 -0
  45. data/dpl-testfairy.gemspec +3 -0
  46. data/dpl-transifex.gemspec +3 -0
  47. data/dpl.gemspec +2 -31
  48. data/gemspec_helper.rb +49 -0
  49. data/lib/dpl/provider.rb +101 -58
  50. data/lib/dpl/version.rb +1 -1
  51. data/spec/provider_spec.rb +15 -34
  52. metadata +76 -107
  53. data/lib/dpl/provider/anynines.rb +0 -13
  54. data/lib/dpl/provider/appfog.rb +0 -21
  55. data/lib/dpl/provider/atlas.rb +0 -108
  56. data/lib/dpl/provider/azure_webapps.rb +0 -48
  57. data/lib/dpl/provider/bintray.rb +0 -509
  58. data/lib/dpl/provider/bitballoon.rb +0 -22
  59. data/lib/dpl/provider/bluemix_cloud_foundry.rb +0 -23
  60. data/lib/dpl/provider/boxfuse.rb +0 -57
  61. data/lib/dpl/provider/catalyze.rb +0 -49
  62. data/lib/dpl/provider/chef_supermarket.rb +0 -85
  63. data/lib/dpl/provider/cloud66.rb +0 -38
  64. data/lib/dpl/provider/cloud_files.rb +0 -38
  65. data/lib/dpl/provider/cloud_foundry.rb +0 -43
  66. data/lib/dpl/provider/code_deploy.rb +0 -154
  67. data/lib/dpl/provider/deis.rb +0 -128
  68. data/lib/dpl/provider/divshot.rb +0 -23
  69. data/lib/dpl/provider/elastic_beanstalk.rb +0 -195
  70. data/lib/dpl/provider/engine_yard.rb +0 -90
  71. data/lib/dpl/provider/firebase.rb +0 -27
  72. data/lib/dpl/provider/gae.rb +0 -97
  73. data/lib/dpl/provider/gcs.rb +0 -59
  74. data/lib/dpl/provider/hackage.rb +0 -29
  75. data/lib/dpl/provider/heroku.rb +0 -18
  76. data/lib/dpl/provider/heroku/api.rb +0 -98
  77. data/lib/dpl/provider/heroku/generic.rb +0 -94
  78. data/lib/dpl/provider/heroku/git.rb +0 -28
  79. data/lib/dpl/provider/lambda.rb +0 -236
  80. data/lib/dpl/provider/launchpad.rb +0 -48
  81. data/lib/dpl/provider/modulus.rb +0 -23
  82. data/lib/dpl/provider/npm.rb +0 -64
  83. data/lib/dpl/provider/openshift.rb +0 -59
  84. data/lib/dpl/provider/ops_works.rb +0 -132
  85. data/lib/dpl/provider/packagecloud.rb +0 -144
  86. data/lib/dpl/provider/pages.rb +0 -212
  87. data/lib/dpl/provider/puppet_forge.rb +0 -43
  88. data/lib/dpl/provider/pypi.rb +0 -103
  89. data/lib/dpl/provider/releases.rb +0 -139
  90. data/lib/dpl/provider/rubygems.rb +0 -51
  91. data/lib/dpl/provider/s3.rb +0 -123
  92. data/lib/dpl/provider/scalingo.rb +0 -97
  93. data/lib/dpl/provider/script.rb +0 -29
  94. data/lib/dpl/provider/surge.rb +0 -33
  95. data/lib/dpl/provider/testfairy.rb +0 -111
  96. data/lib/dpl/provider/transifex.rb +0 -45
  97. data/spec/provider/anynines_spec.rb +0 -20
  98. data/spec/provider/appfog_spec.rb +0 -35
  99. data/spec/provider/atlas_spec.rb +0 -99
  100. data/spec/provider/azure_webapps_spec.rb +0 -95
  101. data/spec/provider/bintray_spec.rb +0 -259
  102. data/spec/provider/bitballoon_spec.rb +0 -32
  103. data/spec/provider/bluemixcloudfoundry_spec.rb +0 -23
  104. data/spec/provider/boxfuse_spec.rb +0 -16
  105. data/spec/provider/catalyze_spec.rb +0 -39
  106. data/spec/provider/chef_supermarket_spec.rb +0 -51
  107. data/spec/provider/cloud66_spec.rb +0 -44
  108. data/spec/provider/cloud_files_spec.rb +0 -88
  109. data/spec/provider/cloudfoundry_spec.rb +0 -71
  110. data/spec/provider/code_deploy_spec.rb +0 -366
  111. data/spec/provider/deis_spec.rb +0 -116
  112. data/spec/provider/divshot_spec.rb +0 -28
  113. data/spec/provider/elastic_beanstalk_spec.rb +0 -209
  114. data/spec/provider/firebase_spec.rb +0 -40
  115. data/spec/provider/gae_spec.rb +0 -26
  116. data/spec/provider/gcs_spec.rb +0 -115
  117. data/spec/provider/hackage_spec.rb +0 -47
  118. data/spec/provider/heroku_spec.rb +0 -357
  119. data/spec/provider/lambda_spec.rb +0 -432
  120. data/spec/provider/launchpad_spec.rb +0 -33
  121. data/spec/provider/modulus_spec.rb +0 -29
  122. data/spec/provider/npm_spec.rb +0 -95
  123. data/spec/provider/openshift_spec.rb +0 -91
  124. data/spec/provider/ops_works_spec.rb +0 -127
  125. data/spec/provider/packagecloud_spec.rb +0 -56
  126. data/spec/provider/puppet_forge_spec.rb +0 -60
  127. data/spec/provider/pypi_spec.rb +0 -105
  128. data/spec/provider/releases_spec.rb +0 -303
  129. data/spec/provider/rubygems_spec.rb +0 -106
  130. data/spec/provider/s3_spec.rb +0 -174
  131. data/spec/provider/scalingo_spec.rb +0 -64
  132. data/spec/provider/script_spec.rb +0 -26
  133. data/spec/provider/surge_spec.rb +0 -15
  134. data/spec/provider/testfairy_spec.rb +0 -65
  135. data/spec/provider/transifex_spec.rb +0 -110
@@ -1,48 +0,0 @@
1
- module DPL
2
- class Provider
3
- class AzureWebApps < Provider
4
- def config
5
- {
6
- "username" => options[:username] || context.env['AZURE_WA_USERNAME'],
7
- "password" => options[:password] || context.env['AZURE_WA_PASSWORD'],
8
- "site" => options[:site] || context.env['AZURE_WA_SITE'],
9
- "slot" => options[:slot] || context.env['AZURE_WA_SLOT']
10
- }
11
- end
12
-
13
- def git_target
14
- "https://#{config['username']}:#{config['password']}@#{config['slot'] || config['site']}.scm.azurewebsites.net:443/#{config['site']}.git"
15
- end
16
-
17
- def needs_key?
18
- false
19
- end
20
-
21
- def check_app
22
- end
23
-
24
- def check_auth
25
- error "missing Azure Git Deployment username" unless config['username']
26
- error "missing Azure Git Deployment password" unless config['password']
27
- error "missing Azure Web App name" unless config['site']
28
- end
29
-
30
- def push_app
31
- log "Deploying to Azure Web App '#{config['slot'] || config['site']}'"
32
-
33
- if !!options[:skip_cleanup]
34
- log "Skipping Cleanup"
35
- context.shell "git checkout HEAD"
36
- context.shell "git add . --all --force"
37
- context.shell "git commit -m \"Skip Cleanup Commit\""
38
- end
39
-
40
- if !!options[:verbose]
41
- context.shell "git push --force --quiet #{git_target} HEAD:refs/heads/master"
42
- else
43
- context.shell "git push --force --quiet #{git_target} HEAD:refs/heads/master > /dev/null 2>&1"
44
- end
45
- end
46
- end
47
- end
48
- end
@@ -1,509 +0,0 @@
1
- require 'json'
2
- require 'net/http'
3
- require "uri"
4
- require 'find'
5
-
6
- module DPL
7
- class Provider
8
- class Bintray < Provider
9
- def check_auth
10
- end
11
-
12
- def needs_key?
13
- false
14
- end
15
-
16
- attr_accessor :test_mode
17
- attr_reader :user
18
- attr_reader :key
19
- attr_reader :file
20
- attr_reader :passphrase
21
- attr_reader :url
22
- attr_reader :dry_run
23
- attr_reader :descriptor
24
-
25
- def initialize(*args)
26
- super(*args)
27
- @test_mode = false
28
- @user = options[:user]
29
- @key = options[:key]
30
- @url = options[:url]
31
- @file = options[:file]
32
- @passphrase = options[:passphrase]
33
- @dry_run = options[:dry_run]
34
-
35
- if @user.nil?
36
- abort("The 'user' argument is required")
37
- end
38
- if @key.nil?
39
- abort("The 'key' argument is required")
40
- end
41
- if @file.nil?
42
- abort("The 'file' argument is required")
43
- end
44
- if @url.nil?
45
- @url = 'https://api.bintray.com'
46
- end
47
- if @dry_run.nil?
48
- @dry_run = false
49
- end
50
- end
51
-
52
- def read_descriptor
53
- log "Reading descriptor file: #{file}"
54
- @descriptor = JSON.parse(File.read(file))
55
- end
56
-
57
- def descriptor=(json)
58
- @descriptor = JSON.parse(json)
59
- end
60
-
61
- def head_request(path)
62
- url = URI.parse(self.url)
63
- req = Net::HTTP::Head.new(path)
64
- req.basic_auth user, key
65
-
66
- sock = Net::HTTP.new(url.host, url.port)
67
- sock.use_ssl = true
68
- res = sock.start {|http| http.request(req) }
69
-
70
- return res
71
- end
72
-
73
- def post_request(path, body)
74
- req = Net::HTTP::Post.new(path)
75
- req.add_field('Content-Type', 'application/json')
76
- req.basic_auth user, key
77
- if !body.nil?
78
- req.body = body.to_json
79
- end
80
-
81
- url = URI.parse(self.url)
82
- sock = Net::HTTP.new(url.host, url.port)
83
- sock.use_ssl = true
84
- res = sock.start {|http| http.request(req) }
85
- return res
86
- end
87
-
88
- def put_file_request(local_file_path, upload_path, matrix_params)
89
- url = URI.parse(self.url)
90
-
91
- file = File.open(local_file_path, 'rb')
92
- data = file.read()
93
- http = Net::HTTP.new(url.host, url.port)
94
- http.use_ssl = true
95
-
96
- params = ''
97
- if !matrix_params.nil?
98
- matrix_params.each do |key, val|
99
- params << ";#{key}=#{val}"
100
- end
101
- upload_path << params
102
- end
103
-
104
- request = Net::HTTP::Put.new("#{upload_path}")
105
- request.basic_auth user, key
106
- request.body = data
107
-
108
- return http.request(request)
109
- end
110
-
111
- def upload_file(artifact)
112
- log "Uploading file '#{artifact.local_path}' to #{artifact.upload_path}"
113
-
114
- if dry_run
115
- return
116
- end
117
-
118
- package = descriptor["package"]
119
- version = descriptor["version"]
120
- package_name = package["name"]
121
- subject = package["subject"]
122
- repo = package["repo"]
123
- version_name = version["name"]
124
-
125
- path = "/content/#{subject}/#{repo}/#{package_name}/#{version_name}/#{artifact.upload_path}"
126
- res = put_file_request(artifact.local_path, path, artifact.matrix_params)
127
- log_bintray_response(res)
128
- end
129
-
130
- def package_exists_path
131
- package = descriptor["package"]
132
- subject = package["subject"]
133
- name = package["name"]
134
- repo = package["repo"]
135
- return "/packages/#{subject}/#{repo}/#{name}"
136
- end
137
-
138
- def package_exists?
139
- path = package_exists_path
140
- if !dry_run
141
- res = head_request(path)
142
- code = res.code.to_i
143
- else
144
- code = 404
145
- end
146
-
147
- if code == 404
148
- return false
149
- end
150
- if code == 201 || code == 200
151
- return true
152
- end
153
- name = descriptor["package"]["name"]
154
- abort("Unexpected HTTP response code #{code} returned from Bintray while checking if package '#{name}' exists. " +
155
- "Response message: #{res.message}")
156
- end
157
-
158
- def version_exists_path
159
- package = descriptor["package"]
160
- version = descriptor["version"]
161
- package_name = package["name"]
162
- subject = package["subject"]
163
- repo = package["repo"]
164
- version_name = version["name"]
165
-
166
- return "/packages/#{subject}/#{repo}/#{package_name}/versions/#{version_name}"
167
- end
168
-
169
- def version_exists?
170
- path = version_exists_path
171
- if !dry_run
172
- res = head_request(path)
173
- code = res.code.to_i
174
- else
175
- code = 404
176
- end
177
-
178
- if code == 404
179
- return false
180
- end
181
- if code == 201 || code == 200
182
- return true
183
- end
184
- version_name = descriptor["version"]["name"]
185
- abort("Unexpected HTTP response code #{code} returned from Bintray while checking if version '#{version_name}' exists. " +
186
- "Response message: #{res.message}")
187
- end
188
-
189
- def create_package
190
- package = descriptor["package"]
191
- repo = package["repo"]
192
- body = {}
193
-
194
- add_to_map(body, package, "name")
195
- add_to_map(body, package, "desc")
196
- add_to_map(body, package, "licenses")
197
- add_to_map(body, package, "labels")
198
- add_to_map(body, package, "vcs_url")
199
- add_to_map(body, package, "website_url")
200
- add_to_map(body, package, "issue_tracker_url")
201
- add_to_map(body, package, "public_download_numbers")
202
- add_to_map(body, package, "public_stats")
203
-
204
- subject = package["subject"]
205
- package_name = package["name"]
206
- log "Creating package '#{package_name}'..."
207
-
208
- path = "/packages/#{subject}/#{repo}"
209
- if !dry_run
210
- res = post_request(path, body)
211
- log_bintray_response(res)
212
- code = res.code.to_i
213
- else
214
- code = 200
215
- end
216
-
217
- if !test_mode
218
- if code == 201 || code == 200
219
- add_package_attributes
220
- end
221
- end
222
- RequestDetails.new(path, body)
223
- end
224
-
225
- def add_package_attributes
226
- package = descriptor["package"]
227
- repo = package["repo"]
228
- subject = package["subject"]
229
- package_name = package["name"]
230
- attributes = package["attributes"]
231
- path = nil
232
- if !attributes.nil?
233
- log "Adding attributes for package '#{package_name}'..."
234
- path = "/packages/#{subject}/#{repo}/#{package_name}/attributes"
235
- if !dry_run
236
- res = post_request(path, attributes)
237
- log_bintray_response(res)
238
- end
239
- end
240
- RequestDetails.new(path, attributes)
241
- end
242
-
243
- def create_version
244
- package = descriptor["package"]
245
- version = descriptor["version"]
246
- repo = package["repo"]
247
- body = {}
248
-
249
- add_to_map(body, version, "name")
250
- add_to_map(body, version, "desc")
251
- add_to_map(body, version, "released")
252
- add_to_map(body, version, "vcs_tag")
253
- add_to_map(body, version, "github_release_notes_file")
254
- add_to_map(body, version, "github_use_tag_release_notes")
255
- add_to_map(body, version, "attributes")
256
-
257
- package_name = package["name"]
258
- subject = package["subject"]
259
- version_name = version["name"]
260
- log "Creating version '#{version_name}'..."
261
-
262
- path = "/packages/#{subject}/#{repo}/#{package_name}/versions"
263
- if !dry_run
264
- res = post_request(path, body)
265
- log_bintray_response(res)
266
- code = res.code.to_i
267
- else
268
- code = 200
269
- end
270
-
271
- if !test_mode
272
- if code == 201 || code == 200
273
- add_version_attributes
274
- end
275
- end
276
- RequestDetails.new(path, body)
277
- end
278
-
279
- def add_version_attributes
280
- package = descriptor["package"]
281
- package_name = package["name"]
282
- subject = package["subject"]
283
- version = descriptor["version"]
284
- version_name = version["name"]
285
- repo = package["repo"]
286
- attributes = version["attributes"]
287
- path = nil
288
- if !attributes.nil?
289
- log "Adding attributes for version '#{version_name}'..."
290
- path = "/packages/#{subject}/#{repo}/#{package_name}/versions/#{version_name}/attributes"
291
- if !dry_run
292
- res = post_request(path, attributes)
293
- log_bintray_response(res)
294
- end
295
- end
296
- RequestDetails.new(path, attributes)
297
- end
298
-
299
- def check_and_create_package
300
- if !package_exists?
301
- create_package
302
- end
303
- end
304
-
305
- def check_and_create_version
306
- if !version_exists?
307
- create_version
308
- end
309
- end
310
-
311
- def upload_files
312
- files = files_to_upload
313
-
314
- files.each do |key, artifact|
315
- upload_file(artifact)
316
- end
317
- end
318
-
319
- def publish_version
320
- publish = descriptor["publish"]
321
- if publish
322
- package = descriptor["package"]
323
- version = descriptor["version"]
324
- repo = package["repo"]
325
- package_name = package["name"]
326
- subject = package["subject"]
327
- version_name = version["name"]
328
-
329
- log "Publishing version '#{version_name}' of package '#{package_name}'..."
330
- path = "/content/#{subject}/#{repo}/#{package_name}/#{version_name}/publish"
331
- if !dry_run
332
- res = post_request(path, nil)
333
- log_bintray_response(res)
334
- end
335
- end
336
- RequestDetails.new(path, nil)
337
- end
338
-
339
- def gpg_sign_version
340
- version = descriptor["version"]
341
- gpg_sign = version["gpgSign"]
342
- if gpg_sign
343
- package = descriptor["package"]
344
- repo = package["repo"]
345
- package_name = package["name"]
346
- subject = package["subject"]
347
- version_name = version["name"]
348
-
349
- body = nil
350
- if !passphrase.nil?
351
- log "Signing version with no passphrase..."
352
- body = {}
353
- body["passphrase"] = passphrase
354
- else
355
- log "Signing version with passphrase..."
356
- end
357
-
358
- path = "/gpg/#{subject}/#{repo}/#{package_name}/versions/#{version_name}"
359
- if !dry_run
360
- res = post_request(path, body)
361
- log_bintray_response(res)
362
- end
363
- RequestDetails.new(path, body)
364
- end
365
- end
366
-
367
- # Get the root path from which to start collecting files to be
368
- # uploaded to Bintray.
369
- def root_path(str)
370
- index = str.index('(')
371
- path = nil
372
- if index.nil? || str.start_with?('(')
373
- path = str
374
- else
375
- path = str[0, index]
376
- end
377
-
378
- if !test_mode && !File.exist?(path)
379
- log "Warning: Path: #{path} does not exist."
380
- return nil
381
- end
382
- return path
383
- end
384
-
385
- # Fills a map with Artifact objects which match
386
- # the include pattern and do not match the exclude pattern.
387
- # The artifacts are files collected from the file system.
388
- def fill_files_map(map, include_pattern, exclude_pattern, upload_pattern, matrix_params)
389
- # Get the root path from which to start collecting the files.
390
- root_path = root_path(include_pattern)
391
- if root_path.nil?
392
- return
393
- end
394
-
395
- # Start scanning the root path recursively.
396
- Find.find(root_path) do |path|
397
- add_if_matches(map, path, include_pattern, exclude_pattern, upload_pattern, matrix_params)
398
- end
399
- end
400
-
401
- def add_if_matches(map, path, include_pattern, exclude_pattern, upload_pattern, matrix_params)
402
- res = path.match(/#{include_pattern}/)
403
-
404
- # If the file matches the include pattern and it is not a directory.
405
- # In case test_mode is set, we do not check if the file exists.
406
- if !res.nil? && (test_mode || File.file?(path))
407
- # If the file does not match the exclude pattern.
408
- if exclude_pattern.nil? || exclude_pattern.empty? || !path.match(/#{exclude_pattern}/)
409
- # Using the capturing groups in the include pattern, replace the $1, $2, ...
410
- # in the upload pattern.
411
- groups = res.captures
412
- replaced_upload_pattern = upload_pattern
413
- for i in 0..groups.size-1
414
- replaced_upload_pattern = replaced_upload_pattern.gsub("$#{i+1}", groups[i])
415
- end
416
- map[path] = Artifact.new(path, replaced_upload_pattern, matrix_params)
417
- end
418
- end
419
- end
420
-
421
- # Returns a map containing Artifact objects.
422
- # The map contains the files to be uploaded to Bintray.
423
- def files_to_upload
424
- upload_files = Hash.new()
425
- files = descriptor["files"]
426
- if files.nil?
427
- return upload_files
428
- end
429
-
430
- files.each { |patterns|
431
- fill_files_map(
432
- upload_files,
433
- patterns["includePattern"],
434
- patterns["excludePattern"],
435
- patterns["uploadPattern"],
436
- patterns["matrixParams"])
437
- }
438
-
439
- return upload_files
440
- end
441
-
442
- def deploy
443
- read_descriptor
444
- check_and_create_package
445
- check_and_create_version
446
- upload_files
447
- gpg_sign_version
448
- publish_version
449
- end
450
-
451
- # Copies a key from one map to another, if the key exists there.
452
- def add_to_map(to_map, from_map, key)
453
- if !from_map[key].nil?
454
- to_map[key] = from_map[key]
455
- end
456
- end
457
-
458
- def log_bintray_response(res)
459
- msg = ''
460
- if !res.body.nil?
461
- begin
462
- response = JSON.parse(res.body)
463
- msg = response["message"]
464
- rescue
465
- end
466
- end
467
-
468
- log "Bintray response: #{res.code.to_i} #{res.message}. #{msg}"
469
- end
470
-
471
- def log(msg)
472
- puts "[Bintray Upload] #{msg}"
473
- end
474
-
475
- # This class represents an artifact (file) to be uploaded to Bintray.
476
- class Artifact
477
- def initialize(local_path, upload_path, matrix_params)
478
- @local_path = local_path
479
- @upload_path = upload_path
480
- @matrix_params = matrix_params
481
- end
482
-
483
- def hash
484
- return @localPath.hash
485
- end
486
-
487
- def eql?(other)
488
- @localPath == other.local_path
489
- end
490
-
491
- attr_reader :local_path
492
- attr_reader :upload_path
493
- attr_reader :matrix_params
494
- end
495
-
496
- # Used to return the path and body of REST requests sent to Bintray.
497
- # Used for testing.
498
- class RequestDetails
499
- def initialize(path, body)
500
- @path = path
501
- @body = body
502
- end
503
-
504
- attr_reader :path
505
- attr_reader :body
506
- end
507
- end
508
- end
509
- end