swagger_autogenerate 1.1.0 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
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