swagger_autogenerate 1.1.0 → 1.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 131bed446c702ccaacd09c8e320b10775c1e5cea7dc9a0d894b675302b2b24d1
4
- data.tar.gz: a3df01d6c6dc46d1f6e38a0fc8a592dafabba1f2bf52ecb85574284230ce9835
3
+ metadata.gz: fa0e0d56334a728cbd835bf8ecf0cf4b2c330eb62aeb92e6b9bc20d1251ed5cd
4
+ data.tar.gz: c5869ad74ec90bffdb1a58bdfbb52645849b14f88e81e876f5b856d280dab536
5
5
  SHA512:
6
- metadata.gz: fca6c316c35e49ebceecb69b0304a9d818ddf5d7b06b128cf02c339b88ebf17e003d5d4e08d7e1b712d699d12e8eb4d6c68fb3273ff35fefc978bdddeb56a7e3
7
- data.tar.gz: b51b77a5ea1b37f800405396483d74d92ba5b5cab4e29e5597ae8f43b42df08982ca9c0c531c0d6caf52caded6a825e3c26f4df356e636deb9614eba0126a85f
6
+ metadata.gz: 7766553dbaa81ee1506f36727411a24e36d9dd7c73bc4733a2bc034be406b2c94e4526f7c73467e1d383cf3e566fecaa6ea592a06627f4a5778dba61cd5f142e
7
+ data.tar.gz: ab857ce41cc465f94b961c61d2f3bbeb48195c8bf5472152c43524384caa57313325b852df8417e2c07489fed8ae0e656c941d9c91a395ea6e16895ace7a990c
data/CHANGELOG.md CHANGED
@@ -10,5 +10,7 @@
10
10
  ## [1.0.8] - 2024-06-03
11
11
  ## [1.0.9] - 2024-06-04
12
12
  ## [1.1.0] - 2024-06-23
13
+ ## [1.1.1] - 2024-06-26
14
+ ## [1.1.2] - 2024-08-17
13
15
 
14
16
  - Initial release
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- swagger_autogenerate (1.1.0)
4
+ swagger_autogenerate (1.1.2)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -1,22 +1,24 @@
1
1
  module SwaggerAutogenerate
2
2
  class Configuration
3
- attr_accessor :with_config, :with_multiple_examples, :with_example_description,
3
+ attr_accessor :with_config, :with_multiple_examples, :with_rspec_examples, :with_example_description,
4
4
  :with_response_description, :swagger_environment_variable,
5
5
  :environment_name, :security, :swagger_config, :response_status
6
6
 
7
7
  def initialize
8
8
  @with_config = true
9
9
  @with_multiple_examples = true
10
+ @with_rspec_examples = true
11
+ # remove this when we do not need it any more
10
12
  @with_example_description = true
11
13
  @with_response_description = true
12
14
  @swagger_environment_variable = 'SWAGGER'
13
15
  @environment_name = :test
14
- @security = security
15
- @swagger_config = swagger_config
16
- @response_status = response_status
16
+ @security = default_security
17
+ @swagger_config = default_swagger_config
18
+ @response_status = default_response_status
17
19
  end
18
20
 
19
- def response_status
21
+ def default_response_status
20
22
  {
21
23
  100 => 'The initial part of the request has been received, and the client should proceed with sending the remainder of the request',
22
24
  101 => 'The server agrees to switch protocols and is acknowledging the client\'s request to change the protocol being used',
@@ -42,7 +44,7 @@ module SwaggerAutogenerate
42
44
  }
43
45
  end
44
46
 
45
- def swagger_config
47
+ def default_swagger_config
46
48
  {
47
49
  'openapi' => '3.0.0',
48
50
  'info' => {
@@ -63,7 +65,7 @@ module SwaggerAutogenerate
63
65
  }
64
66
  end
65
67
 
66
- def security
68
+ def default_security
67
69
  [
68
70
  { 'org_slug' => [] },
69
71
  { 'locale' => [] }
@@ -78,4 +80,9 @@ module SwaggerAutogenerate
78
80
  def self.configure
79
81
  yield(configuration)
80
82
  end
83
+
84
+ def self.extract_description(full_rspec_description)
85
+ parts = full_rspec_description.split(' ')
86
+ parts&.length > 1 ? parts[2..-1].join(" ") : full_rspec_description
87
+ end
81
88
  end
@@ -5,7 +5,7 @@ module SwaggerAutogenerate
5
5
  def initialize(request, response)
6
6
  @with_config = ::SwaggerAutogenerate.configuration.with_config
7
7
  @with_multiple_examples = ::SwaggerAutogenerate.configuration.with_multiple_examples
8
- @with_example_description = ::SwaggerAutogenerate.configuration.with_example_description
8
+ @with_rspec_examples = ::SwaggerAutogenerate.configuration.with_rspec_examples
9
9
  @with_response_description = ::SwaggerAutogenerate.configuration.with_response_description
10
10
  @security = ::SwaggerAutogenerate.configuration.security
11
11
  @swagger_config = ::SwaggerAutogenerate.configuration.swagger_config
@@ -39,7 +39,7 @@ module SwaggerAutogenerate
39
39
  private
40
40
 
41
41
  attr_reader :request, :response, :current_path, :yaml_file, :configuration,
42
- :with_config, :with_multiple_examples, :with_example_description,
42
+ :with_config, :with_multiple_examples, :with_rspec_examples,
43
43
  :with_response_description, :security, :response_status, :swagger_config
44
44
 
45
45
  # main methods
@@ -88,6 +88,13 @@ module SwaggerAutogenerate
88
88
  data['paths'] = paths
89
89
  organize_result(data['paths'])
90
90
  data = data.to_hash
91
+ # handel examples names
92
+ example_title = full_rspec_description.present? ? full_rspec_description : 'example-0'
93
+ old_examples = data['paths'][current_path][request.method.downcase]['responses'][response.status.to_s]['content']['application/json']['examples']
94
+ current_example = old_examples[example_title]
95
+ new_example(example_title, current_example, old_examples, data['paths'], true)
96
+ # result
97
+
91
98
  result = add_quotes_to_dates(YAML.dump(data))
92
99
  file.write(result)
93
100
  end
@@ -209,24 +216,42 @@ module SwaggerAutogenerate
209
216
  }
210
217
  end
211
218
 
212
- def convert_to_multipart(payload)
219
+ def convert_to_multipart(payload, main_key = nil, index = nil)
220
+ payload_keys.push(main_key) if main_key.present?
213
221
  payload.each do |key, value|
214
222
  if value.is_a?(Hash)
215
223
  payload_keys.push(key)
216
224
  convert_to_multipart(value)
225
+ elsif value.is_a?(Array)
226
+ value.each_with_index { |v, index| convert_to_multipart(v, key, index) }
217
227
  else
218
228
  keys = payload_keys.clone
219
229
  first_key = keys.shift
220
- keys.each { |inner_key| first_key = "#{first_key}[#{inner_key}]" }
221
- first_key = "#{first_key}[#{key}]"
230
+ if index.present?
231
+ keys.each { |inner_key| first_key = "#{first_key}[#{inner_key}][#{index}]" }
232
+ else
233
+ keys.each { |inner_key| first_key = "#{first_key}[#{inner_key}]" }
234
+ end
222
235
 
236
+ first_key = "#{first_key}[#{key}]"
223
237
  payload_hash.merge!({ first_key => { 'type' => schema_type(value), 'example' => example(value) } })
224
238
  end
225
239
  end
226
240
  end
227
241
 
228
242
  def content_form_data(data)
229
- convert_to_multipart(data)
243
+ hash_data = {}
244
+ data.map do |key, value|
245
+ if value.is_a?(Hash)
246
+ hash_data.merge!({ key => value })
247
+ elsif value.is_a?(Array)
248
+ value.each_with_index { |v, index| convert_to_multipart(v, key) }
249
+ else
250
+ payload_hash.merge!({ key => { 'type' => schema_type(value), 'example' => example(value) } })
251
+ end
252
+ end
253
+
254
+ convert_to_multipart(hash_data)
230
255
  converted_payload = @payload_hash.clone
231
256
  @payload_hash = nil
232
257
  @payload_keys = nil
@@ -241,10 +266,93 @@ module SwaggerAutogenerate
241
266
  }
242
267
  end
243
268
 
269
+ def json_to_content_form_data(json)
270
+ {
271
+ 'multipart/form-data' => {
272
+ 'schema' => build_properties(json)
273
+ }
274
+ }
275
+ end
276
+
277
+ def build_properties(json)
278
+ case json
279
+ when Hash
280
+ hash_properties = json.transform_values { |value| build_properties(value) if value.present? }
281
+ hash_properties = hash_properties.delete_if { |_k, v| !v.present? }
282
+
283
+ hashs = {
284
+ 'type' => 'object',
285
+ 'properties' => hash_properties
286
+ }
287
+ when Array
288
+ item_schemas = json.map { |item| build_properties(item) }
289
+ merged_schema = merge_array_schemas(item_schemas)
290
+
291
+ if merged_schema[:type] == 'object'
292
+ { 'type' => 'array', 'items' => merged_schema }
293
+ else
294
+ { 'type' => 'array', 'items' => { 'oneOf' => item_schemas.uniq } }
295
+ end
296
+ when String
297
+ { 'type' => 'string', 'example' => json }
298
+ when Integer
299
+ { 'type' => 'integer', 'example' => json }
300
+ when Float
301
+ { 'type' => 'number', 'example' => json }
302
+ when TrueClass, FalseClass
303
+ { 'type' => 'boolean', 'example' => json }
304
+ else
305
+ { 'type' => 'string', 'example' => json.to_s }
306
+ end
307
+ end
308
+
309
+ def merge_array_schemas(schemas)
310
+ return {} if schemas.empty?
311
+
312
+ # Attempt to merge all schemas into a single schema
313
+ schemas.reduce do |merged, schema|
314
+ merge_properties(merged, schema)
315
+ end
316
+ end
317
+
318
+ def merge_properties(old_data, new_data)
319
+ return old_data unless old_data.is_a?(Hash) && new_data.is_a?(Hash)
320
+
321
+ merged = old_data.dup
322
+ new_data.each do |key, value|
323
+ merged[key] = if merged[key].is_a?(Hash) && value.is_a?(Hash)
324
+ merge_properties(merged[key], value)
325
+ else
326
+ value
327
+ end
328
+ end
329
+ merged
330
+ end
331
+
332
+ def content_application_json_schema_properties(data)
333
+ hash_data = {}
334
+ data.map do |key, value|
335
+ if value.is_a?(Hash)
336
+ hash_data.merge!({ key => value })
337
+ elsif value.is_a?(Array)
338
+ value.each_with_index { |v, index| convert_to_multipart(v, key, index) }
339
+ else
340
+ payload_hash.merge!({ key => { 'type' => schema_type(value), 'example' => example(value) } })
341
+ end
342
+ end
343
+
344
+ convert_to_multipart(hash_data)
345
+ converted_payload = @payload_hash.clone
346
+ @payload_hash = nil
347
+ @payload_keys = nil
348
+
349
+ converted_payload
350
+ end
351
+
244
352
  def content_body(data)
245
353
  hash = {}
246
354
  # hash.merge!(content_json(data))
247
- hash.merge!(content_form_data(data))
355
+ hash.merge!(json_to_content_form_data(data))
248
356
 
249
357
  { 'content' => hash }
250
358
  end
@@ -342,19 +450,18 @@ module SwaggerAutogenerate
342
450
  end
343
451
 
344
452
  def content_json_example(data)
345
- hash = {
453
+ example_title = full_rspec_description.present? ? full_rspec_description : 'example-0'
454
+
455
+ {
346
456
  'application/json' => {
347
457
  'schema' => { 'type' => 'object' },
348
458
  'examples' => {
349
- 'example-0' => {
459
+ example_title => {
350
460
  'value' => data
351
461
  }
352
462
  }
353
463
  }
354
464
  }
355
- hash['application/json']['examples']['example-0']['description'] = "payload => #{example_description}" if with_example_description && !example_description.empty?
356
-
357
- hash
358
465
  end
359
466
 
360
467
  def example_description
@@ -387,20 +494,48 @@ module SwaggerAutogenerate
387
494
  @payload_hash ||= {}
388
495
  end
389
496
 
390
- def new_example
391
- current_example = swagger_response[response.status.to_s]['content']['application/json']['examples']['example-0']
392
- old_examples = old_paths[current_path][request.method.downcase]['responses'][response.status.to_s]['content']['application/json']['examples']
393
-
394
- unless old_examples.value?(current_example)
395
- last_example = json_example_plus_one(old_examples.keys.last)
396
- last_example ||= 'example-0'
397
- last_example = 'example-0' unless with_multiple_examples
398
- yaml_file['paths'][current_path][request.method.downcase]['responses'][response.status.to_s]['content']['application/json']['examples'][last_example] = current_example
497
+ def new_example(example_title, current_example, old_examples, all_paths = yaml_file['paths'], with_schema_properties = false)
498
+ if !old_examples.value?(current_example)
499
+ last_example = handel_name_last_example(old_examples)
500
+ last_example ||= example_title
501
+ last_example = example_title unless with_multiple_examples
502
+ all_paths[current_path][request.method.downcase]['responses'][response.status.to_s]['content']['application/json']['examples'][last_example] = current_example
503
+ add_properties_to_schema(last_example, all_paths[current_path])
504
+ elsif with_schema_properties
505
+ add_properties_to_schema(full_rspec_description.present? ? full_rspec_description : 'example-0', all_paths[current_path])
399
506
  end
400
507
 
401
508
  true
402
509
  end
403
510
 
511
+ def handel_name_last_example(old_examples)
512
+ last_example = old_examples.keys.last
513
+ last_example += '-1' if json_example_plus_one(last_example) == last_example
514
+ json_example_plus_one(last_example)
515
+ end
516
+
517
+ def add_properties_to_schema(last_example, main_path = yaml_file['paths'][current_path])
518
+ parameters = {}
519
+ parameters.merge!(request_parameters.values.first, query_parameters.values.first, path_parameters.values.first)
520
+ hash = {
521
+ last_example => build_properties(parameters.as_json)
522
+ }
523
+
524
+ main_path[request.method.downcase]['responses'][response.status.to_s].deep_merge!(
525
+ {
526
+ 'content' => {
527
+ 'application/json' => {
528
+ 'schema' => {
529
+ 'description' => 'These are the payloads for each example',
530
+ 'type' => 'object',
531
+ 'properties' => hash
532
+ }
533
+ }
534
+ }
535
+ }
536
+ )
537
+ end
538
+
404
539
  def apply_yaml_file_changes
405
540
  (check_path || check_method || check_status) &&
406
541
  (check_parameters || check_parameter) &&
@@ -429,24 +564,29 @@ module SwaggerAutogenerate
429
564
  def check_path
430
565
  unless old_paths.key?(current_path)
431
566
  yaml_file['paths'].merge!({ current_path => paths[current_path] })
567
+ update_example_title(true)
432
568
  end
433
569
  end
434
570
 
435
571
  def check_method
436
572
  unless old_paths[current_path].key?(request.method.downcase)
437
573
  yaml_file['paths'][current_path][request.method.downcase] = { 'responses' => swagger_response }
574
+ update_example_title(true)
438
575
  end
439
576
  end
440
577
 
441
578
  def check_status
579
+ example_title = full_rspec_description.present? ? full_rspec_description : 'example-0'
442
580
  if old_paths[current_path][request.method.downcase]['responses'].present?
443
581
  if old_paths[current_path][request.method.downcase]['responses']&.key?(response.status.to_s)
444
- new_example
582
+ update_example_title
445
583
  else
446
584
  yaml_file['paths'][current_path][request.method.downcase]['responses'].merge!(swagger_response)
585
+ update_example_title(true)
447
586
  end
448
587
  else
449
588
  yaml_file['paths'][current_path][request.method.downcase]['responses'] = swagger_response
589
+ update_example_title
450
590
  end
451
591
  end
452
592
 
@@ -472,12 +612,31 @@ module SwaggerAutogenerate
472
612
 
473
613
  def check_request_body
474
614
  if paths[current_path][request.method.downcase]['requestBody'].present?
475
- param_names = paths[current_path][request.method.downcase]['requestBody']['content']['multipart/form-data']['schema']['properties'].keys - yaml_file['paths'][current_path][request.method.downcase]['requestBody']['content']['multipart/form-data']['schema']['properties'].keys
476
- param_names.each do |param_name|
477
- param = paths[current_path][request.method.downcase]['requestBody']['content']['multipart/form-data']['schema']['properties'].select { |parameter| parameter == param_name }
478
- yaml_file['paths'][current_path][request.method.downcase]['requestBody']['content']['multipart/form-data']['schema']['properties'].merge!(param)
615
+ param_current_hash = paths[current_path][request.method.downcase]['requestBody']['content']['multipart/form-data']['schema']['properties']
616
+ param_current_file = yaml_file['paths'][current_path][request.method.downcase]['requestBody']['content']['multipart/form-data']['schema']['properties']
617
+ if param_current_hash.present? && param_current_file.present?
618
+ param_names = param_current_hash.keys - param_current_file.keys
619
+ param_names.each do |param_name|
620
+ param = paths[current_path][request.method.downcase]['requestBody']['content']['multipart/form-data']['schema']['properties'].select { |parameter| parameter == param_name }
621
+ yaml_file['paths'][current_path][request.method.downcase]['requestBody']['content']['multipart/form-data']['schema']['properties'].merge!(param)
622
+ end
479
623
  end
480
624
  end
481
625
  end
626
+
627
+ def update_example_title(with_schema_properties = false)
628
+ example_title = full_rspec_description.present? ? full_rspec_description : 'example-0'
629
+ current_example = swagger_response[response.status.to_s]['content']['application/json']['examples'][example_title]
630
+ old_examples = old_paths[current_path][request.method.downcase]['responses'][response.status.to_s]['content']['application/json']['examples']
631
+ new_example(example_title, current_example, old_examples, yaml_file['paths'], with_schema_properties)
632
+ end
633
+
634
+ def full_rspec_description
635
+ with_rspec_examples ? SwaggerAutogenerate::SwaggerTrace.rspec_description : nil
636
+ end
637
+
638
+ class << self
639
+ attr_accessor :rspec_description
640
+ end
482
641
  end
483
642
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SwaggerAutogenerate
4
- VERSION = "1.1.0"
4
+ VERSION = "1.1.2"
5
5
  end
@@ -8,9 +8,23 @@ module SwaggerAutogenerate
8
8
  def process_action(*args)
9
9
  super
10
10
 
11
- if ENV[SwaggerTrace.swagger_environment_variable].present? && Rails.env.send("#{SwaggerTrace.environment_name.to_s}?")
11
+ if SwaggerAutogenerate.allow_swagger?
12
12
  SwaggerTrace.new(request, response).call
13
13
  end
14
14
  end
15
15
  end
16
+
17
+ def self.allow_swagger?
18
+ ENV[SwaggerTrace.swagger_environment_variable].present? && Rails.env.send("#{SwaggerTrace.environment_name.to_s}?")
19
+ end
20
+ end
21
+
22
+ if defined?(RSpec) && SwaggerAutogenerate.allow_swagger?
23
+ require 'rspec/rails'
24
+
25
+ RSpec.configure do |config|
26
+ config.before(:each) do |example|
27
+ SwaggerAutogenerate::SwaggerTrace.rspec_description = SwaggerAutogenerate.extract_description(example.metadata[:full_description])
28
+ end
29
+ end
16
30
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: swagger_autogenerate
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - MohammedBuraiah
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-06-23 00:00:00.000000000 Z
11
+ date: 2024-08-17 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Generating Swagger YAML Automatically Based on Existing Test Cases in
14
14
  Ruby on Rails