swagger_autogenerate 1.1.1 → 1.2.0

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: 2a323ab35e5b839c6b85294fdf080ce0053fe43854eafbc1d1046b26cf14b7f2
4
- data.tar.gz: 996cd6d73b26711cc59cefe81f720fb747d1a38d5442fa713b3284528f3b8d2b
3
+ metadata.gz: '08b276dd458b54318a75f32c666d40840602065d89a8fa26e7ffac44341e0f15'
4
+ data.tar.gz: bacd1e78fe71a2909d112901a9e6ba2900117b7e2a45522b1d25f11b542aa624
5
5
  SHA512:
6
- metadata.gz: 5794de7918cd298fab142696ff91a6873563fc2a31f6fa9ea60d8ea5a8c483c4467f64c5736f97ebdb92509059ab888032de8d903e8ef1caea486796384693b9
7
- data.tar.gz: 82593525706f167db50f96ead26c6e6ef4f6f1ba5911b761838bd5bf6ab0772d3cd9378fd8b4e1648d9fc0bf85a87868078bfe642175fd7994c7998258a3dfa5
6
+ metadata.gz: 9f6c2c1c285f982a2677daf6d90040bed5682595fd65ee690ac2e01d188a37bc4afca6f4531fc4e8daad142dd5098a54d4dcb336c58ebc97e2ec305afba9eff7
7
+ data.tar.gz: 4c5d8642ac585f043cab7193e3eb9fb7fbe3c027c41d6bcdae6b17b5f6b905a4559469db54f166a9014a4283f9c1d798968a30f18c1ee38160c4579985d5626a
data/CHANGELOG.md CHANGED
@@ -11,5 +11,7 @@
11
11
  ## [1.0.9] - 2024-06-04
12
12
  ## [1.1.0] - 2024-06-23
13
13
  ## [1.1.1] - 2024-06-26
14
+ ## [1.1.2] - 2024-08-17
15
+ ## [1.2.0] - 2024-09-08
14
16
 
15
17
  - Initial release
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- swagger_autogenerate (1.1.1)
4
+ swagger_autogenerate (1.2.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -64,7 +64,7 @@ This file should contain the test scenarios for each action (e.g., index, show,
64
64
 
65
65
  3) Run the spec code using the rspec command and set the environment variable SWAGGER to the desired YAML file name. For example:
66
66
  ```
67
- SWAGGER='employee_apis.yaml' rspec spec/your_path/employees_controller_spec.rb
67
+ SWAGGER_PATH='employee_apis.yaml' rspec spec/your_path/employees_controller_spec.rb
68
68
  ```
69
69
  4) This command runs the spec file and instructs the swagger_autogenerate gem to generate Swagger YAML documentation and save it to the file named employee_apis.yaml.
70
70
  5) Once the command finishes executing, you will have the Swagger YAML documentation generated based on the test scenarios in the employees_controller_spec.rb file.
@@ -1,15 +1,19 @@
1
1
  module SwaggerAutogenerate
2
2
  class Configuration
3
- attr_accessor :with_config, :with_multiple_examples, :with_example_description,
4
- :with_response_description, :swagger_environment_variable,
5
- :environment_name, :security, :swagger_config, :response_status
3
+ attr_accessor :with_config, :with_multiple_examples, :with_rspec_examples, :with_example_description,
4
+ :with_response_description, :swagger_path_environment_variable, :generate_swagger_environment_variable,
5
+ :default_path, :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
- @swagger_environment_variable = 'SWAGGER'
14
+ @swagger_path_environment_variable = 'SWAGGER_PATH'
15
+ @generate_swagger_environment_variable = 'SWAGGER_GENERATE'
16
+ @default_path = 'swagger'
13
17
  @environment_name = :test
14
18
  @security = default_security
15
19
  @swagger_config = default_swagger_config
@@ -78,4 +82,9 @@ module SwaggerAutogenerate
78
82
  def self.configure
79
83
  yield(configuration)
80
84
  end
85
+
86
+ def self.extract_description(full_rspec_description)
87
+ parts = full_rspec_description.split(' ')
88
+ parts&.length > 1 ? parts[2..-1].join(" ") : full_rspec_description
89
+ end
81
90
  end
@@ -5,11 +5,12 @@ 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
12
12
  @response_status = ::SwaggerAutogenerate.configuration.response_status
13
+ @default_path = ::SwaggerAutogenerate.configuration.default_path
13
14
  @request = request
14
15
  @response = response
15
16
  @@paths = {}
@@ -20,12 +21,20 @@ module SwaggerAutogenerate
20
21
  write_swagger_trace
21
22
  end
22
23
 
23
- def self.swagger_environment_variable
24
- ::SwaggerAutogenerate.configuration.swagger_environment_variable
24
+ def self.swagger_path_environment_variable
25
+ ::SwaggerAutogenerate.configuration.swagger_path_environment_variable
25
26
  end
26
27
 
27
- def swagger_environment_variable
28
- SwaggerTrace.swagger_environment_variable
28
+ def swagger_path_environment_variable
29
+ SwaggerTrace.swagger_path_environment_variable
30
+ end
31
+
32
+ def self.generate_swagger_environment_variable
33
+ ::SwaggerAutogenerate.configuration.generate_swagger_environment_variable
34
+ end
35
+
36
+ def generate_swagger_environment_variable
37
+ SwaggerTrace.generate_swagger_environment_variable
29
38
  end
30
39
 
31
40
  def self.environment_name
@@ -39,8 +48,8 @@ module SwaggerAutogenerate
39
48
  private
40
49
 
41
50
  attr_reader :request, :response, :current_path, :yaml_file, :configuration,
42
- :with_config, :with_multiple_examples, :with_example_description,
43
- :with_response_description, :security, :response_status, :swagger_config
51
+ :with_config, :with_multiple_examples, :with_rspec_examples,
52
+ :with_response_description, :security, :response_status, :swagger_config, :default_path
44
53
 
45
54
  # main methods
46
55
 
@@ -88,6 +97,13 @@ module SwaggerAutogenerate
88
97
  data['paths'] = paths
89
98
  organize_result(data['paths'])
90
99
  data = data.to_hash
100
+ # handel examples names
101
+ example_title = full_rspec_description.present? ? full_rspec_description : 'example-0'
102
+ old_examples = data['paths'][current_path][request.method.downcase]['responses'][response.status.to_s]['content']['application/json']['examples']
103
+ current_example = old_examples[example_title]
104
+ new_example(example_title, current_example, old_examples, data['paths'], true)
105
+ # result
106
+
91
107
  result = add_quotes_to_dates(YAML.dump(data))
92
108
  file.write(result)
93
109
  end
@@ -209,17 +225,24 @@ module SwaggerAutogenerate
209
225
  }
210
226
  end
211
227
 
212
- def convert_to_multipart(payload)
228
+ def convert_to_multipart(payload, main_key = nil, index = nil)
229
+ payload_keys.push(main_key) if main_key.present?
213
230
  payload.each do |key, value|
214
231
  if value.is_a?(Hash)
215
232
  payload_keys.push(key)
216
233
  convert_to_multipart(value)
234
+ elsif value.is_a?(Array)
235
+ value.each_with_index { |v, index| convert_to_multipart(v, key, index) }
217
236
  else
218
237
  keys = payload_keys.clone
219
238
  first_key = keys.shift
220
- keys.each { |inner_key| first_key = "#{first_key}[#{inner_key}]" }
221
- first_key = "#{first_key}[#{key}]"
239
+ if index.present?
240
+ keys.each { |inner_key| first_key = "#{first_key}[#{inner_key}][#{index}]" }
241
+ else
242
+ keys.each { |inner_key| first_key = "#{first_key}[#{inner_key}]" }
243
+ end
222
244
 
245
+ first_key = "#{first_key}[#{key}]"
223
246
  payload_hash.merge!({ first_key => { 'type' => schema_type(value), 'example' => example(value) } })
224
247
  end
225
248
  end
@@ -230,6 +253,8 @@ module SwaggerAutogenerate
230
253
  data.map do |key, value|
231
254
  if value.is_a?(Hash)
232
255
  hash_data.merge!({ key => value })
256
+ elsif value.is_a?(Array)
257
+ value.each_with_index { |v, index| convert_to_multipart(v, key) }
233
258
  else
234
259
  payload_hash.merge!({ key => { 'type' => schema_type(value), 'example' => example(value) } })
235
260
  end
@@ -250,10 +275,93 @@ module SwaggerAutogenerate
250
275
  }
251
276
  end
252
277
 
278
+ def json_to_content_form_data(json)
279
+ {
280
+ 'multipart/form-data' => {
281
+ 'schema' => build_properties(json)
282
+ }
283
+ }
284
+ end
285
+
286
+ def build_properties(json)
287
+ case json
288
+ when Hash
289
+ hash_properties = json.transform_values { |value| build_properties(value) if value.present? }
290
+ hash_properties = hash_properties.delete_if { |_k, v| !v.present? }
291
+
292
+ hashs = {
293
+ 'type' => 'object',
294
+ 'properties' => hash_properties
295
+ }
296
+ when Array
297
+ item_schemas = json.map { |item| build_properties(item) }
298
+ merged_schema = merge_array_schemas(item_schemas)
299
+
300
+ if merged_schema[:type] == 'object'
301
+ { 'type' => 'array', 'items' => merged_schema }
302
+ else
303
+ { 'type' => 'array', 'items' => { 'oneOf' => item_schemas.uniq } }
304
+ end
305
+ when String
306
+ { 'type' => 'string', 'example' => json }
307
+ when Integer
308
+ { 'type' => 'integer', 'example' => json }
309
+ when Float
310
+ { 'type' => 'number', 'example' => json }
311
+ when TrueClass, FalseClass
312
+ { 'type' => 'boolean', 'example' => json }
313
+ else
314
+ { 'type' => 'string', 'example' => json.to_s }
315
+ end
316
+ end
317
+
318
+ def merge_array_schemas(schemas)
319
+ return {} if schemas.empty?
320
+
321
+ # Attempt to merge all schemas into a single schema
322
+ schemas.reduce do |merged, schema|
323
+ merge_properties(merged, schema)
324
+ end
325
+ end
326
+
327
+ def merge_properties(old_data, new_data)
328
+ return old_data unless old_data.is_a?(Hash) && new_data.is_a?(Hash)
329
+
330
+ merged = old_data.dup
331
+ new_data.each do |key, value|
332
+ merged[key] = if merged[key].is_a?(Hash) && value.is_a?(Hash)
333
+ merge_properties(merged[key], value)
334
+ else
335
+ value
336
+ end
337
+ end
338
+ merged
339
+ end
340
+
341
+ def content_application_json_schema_properties(data)
342
+ hash_data = {}
343
+ data.map do |key, value|
344
+ if value.is_a?(Hash)
345
+ hash_data.merge!({ key => value })
346
+ elsif value.is_a?(Array)
347
+ value.each_with_index { |v, index| convert_to_multipart(v, key, index) }
348
+ else
349
+ payload_hash.merge!({ key => { 'type' => schema_type(value), 'example' => example(value) } })
350
+ end
351
+ end
352
+
353
+ convert_to_multipart(hash_data)
354
+ converted_payload = @payload_hash.clone
355
+ @payload_hash = nil
356
+ @payload_keys = nil
357
+
358
+ converted_payload
359
+ end
360
+
253
361
  def content_body(data)
254
362
  hash = {}
255
363
  # hash.merge!(content_json(data))
256
- hash.merge!(content_form_data(data))
364
+ hash.merge!(json_to_content_form_data(data))
257
365
 
258
366
  { 'content' => hash }
259
367
  end
@@ -332,10 +440,14 @@ module SwaggerAutogenerate
332
440
  def swagger_location
333
441
  return @swagger_location if instance_variable_defined?(:@swagger_location)
334
442
 
335
- if ENV[swagger_environment_variable].include?('.yaml') || ENV[swagger_environment_variable].include?('.yml')
336
- @swagger_location = Rails.root.join(ENV.fetch(swagger_environment_variable, nil).to_s).to_s
443
+ if ENV[generate_swagger_environment_variable].present?
444
+ directory_path = Rails.root.join(default_path).to_s
445
+ FileUtils.mkdir_p(directory_path) unless File.directory?(directory_path)
446
+ @swagger_location = "#{directory_path}/#{tags.first}.yaml"
447
+ elsif ENV[swagger_path_environment_variable].include?('.yaml') || ENV[swagger_path_environment_variable].include?('.yml')
448
+ @swagger_location = Rails.root.join(ENV.fetch(swagger_path_environment_variable, nil).to_s).to_s
337
449
  else
338
- directory_path = Rails.root.join(ENV.fetch(swagger_environment_variable, nil).to_s).to_s
450
+ directory_path = Rails.root.join(ENV.fetch(swagger_path_environment_variable, nil).to_s).to_s
339
451
  FileUtils.mkdir_p(directory_path) unless File.directory?(directory_path)
340
452
  @swagger_location = "#{directory_path}/#{tags.first}.yaml"
341
453
  end
@@ -351,19 +463,18 @@ module SwaggerAutogenerate
351
463
  end
352
464
 
353
465
  def content_json_example(data)
354
- hash = {
466
+ example_title = full_rspec_description.present? ? full_rspec_description : 'example-0'
467
+
468
+ {
355
469
  'application/json' => {
356
470
  'schema' => { 'type' => 'object' },
357
471
  'examples' => {
358
- 'example-0' => {
472
+ example_title => {
359
473
  'value' => data
360
474
  }
361
475
  }
362
476
  }
363
477
  }
364
- hash['application/json']['examples']['example-0']['description'] = "payload => #{example_description}" if with_example_description && !example_description.empty?
365
-
366
- hash
367
478
  end
368
479
 
369
480
  def example_description
@@ -396,20 +507,48 @@ module SwaggerAutogenerate
396
507
  @payload_hash ||= {}
397
508
  end
398
509
 
399
- def new_example
400
- current_example = swagger_response[response.status.to_s]['content']['application/json']['examples']['example-0']
401
- old_examples = old_paths[current_path][request.method.downcase]['responses'][response.status.to_s]['content']['application/json']['examples']
402
-
403
- unless old_examples.value?(current_example)
404
- last_example = json_example_plus_one(old_examples.keys.last)
405
- last_example ||= 'example-0'
406
- last_example = 'example-0' unless with_multiple_examples
407
- yaml_file['paths'][current_path][request.method.downcase]['responses'][response.status.to_s]['content']['application/json']['examples'][last_example] = current_example
510
+ def new_example(example_title, current_example, old_examples, all_paths = yaml_file['paths'], with_schema_properties = false)
511
+ if !old_examples.value?(current_example)
512
+ last_example = handel_name_last_example(old_examples)
513
+ last_example ||= example_title
514
+ last_example = example_title unless with_multiple_examples
515
+ all_paths[current_path][request.method.downcase]['responses'][response.status.to_s]['content']['application/json']['examples'][last_example] = current_example
516
+ add_properties_to_schema(last_example, all_paths[current_path])
517
+ elsif with_schema_properties
518
+ add_properties_to_schema(full_rspec_description.present? ? full_rspec_description : 'example-0', all_paths[current_path])
408
519
  end
409
520
 
410
521
  true
411
522
  end
412
523
 
524
+ def handel_name_last_example(old_examples)
525
+ last_example = old_examples.keys.last
526
+ last_example += '-1' if json_example_plus_one(last_example) == last_example
527
+ json_example_plus_one(last_example)
528
+ end
529
+
530
+ def add_properties_to_schema(last_example, main_path = yaml_file['paths'][current_path])
531
+ parameters = {}
532
+ parameters.merge!(request_parameters.values.first, query_parameters.values.first, path_parameters.values.first)
533
+ hash = {
534
+ last_example => build_properties(parameters.as_json)
535
+ }
536
+
537
+ main_path[request.method.downcase]['responses'][response.status.to_s].deep_merge!(
538
+ {
539
+ 'content' => {
540
+ 'application/json' => {
541
+ 'schema' => {
542
+ 'description' => 'These are the payloads for each example',
543
+ 'type' => 'object',
544
+ 'properties' => hash
545
+ }
546
+ }
547
+ }
548
+ }
549
+ )
550
+ end
551
+
413
552
  def apply_yaml_file_changes
414
553
  (check_path || check_method || check_status) &&
415
554
  (check_parameters || check_parameter) &&
@@ -438,24 +577,29 @@ module SwaggerAutogenerate
438
577
  def check_path
439
578
  unless old_paths.key?(current_path)
440
579
  yaml_file['paths'].merge!({ current_path => paths[current_path] })
580
+ update_example_title(true)
441
581
  end
442
582
  end
443
583
 
444
584
  def check_method
445
585
  unless old_paths[current_path].key?(request.method.downcase)
446
586
  yaml_file['paths'][current_path][request.method.downcase] = { 'responses' => swagger_response }
587
+ update_example_title(true)
447
588
  end
448
589
  end
449
590
 
450
591
  def check_status
592
+ example_title = full_rspec_description.present? ? full_rspec_description : 'example-0'
451
593
  if old_paths[current_path][request.method.downcase]['responses'].present?
452
594
  if old_paths[current_path][request.method.downcase]['responses']&.key?(response.status.to_s)
453
- new_example
595
+ update_example_title
454
596
  else
455
597
  yaml_file['paths'][current_path][request.method.downcase]['responses'].merge!(swagger_response)
598
+ update_example_title(true)
456
599
  end
457
600
  else
458
601
  yaml_file['paths'][current_path][request.method.downcase]['responses'] = swagger_response
602
+ update_example_title
459
603
  end
460
604
  end
461
605
 
@@ -481,12 +625,31 @@ module SwaggerAutogenerate
481
625
 
482
626
  def check_request_body
483
627
  if paths[current_path][request.method.downcase]['requestBody'].present?
484
- 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
485
- param_names.each do |param_name|
486
- param = paths[current_path][request.method.downcase]['requestBody']['content']['multipart/form-data']['schema']['properties'].select { |parameter| parameter == param_name }
487
- yaml_file['paths'][current_path][request.method.downcase]['requestBody']['content']['multipart/form-data']['schema']['properties'].merge!(param)
628
+ param_current_hash = paths[current_path][request.method.downcase]['requestBody']['content']['multipart/form-data']['schema']['properties']
629
+ param_current_file = yaml_file['paths'][current_path][request.method.downcase]['requestBody']['content']['multipart/form-data']['schema']['properties']
630
+ if param_current_hash.present? && param_current_file.present?
631
+ param_names = param_current_hash.keys - param_current_file.keys
632
+ param_names.each do |param_name|
633
+ param = paths[current_path][request.method.downcase]['requestBody']['content']['multipart/form-data']['schema']['properties'].select { |parameter| parameter == param_name }
634
+ yaml_file['paths'][current_path][request.method.downcase]['requestBody']['content']['multipart/form-data']['schema']['properties'].merge!(param)
635
+ end
488
636
  end
489
637
  end
490
638
  end
639
+
640
+ def update_example_title(with_schema_properties = false)
641
+ example_title = full_rspec_description.present? ? full_rspec_description : 'example-0'
642
+ current_example = swagger_response[response.status.to_s]['content']['application/json']['examples'][example_title]
643
+ old_examples = old_paths[current_path][request.method.downcase]['responses'][response.status.to_s]['content']['application/json']['examples']
644
+ new_example(example_title, current_example, old_examples, yaml_file['paths'], with_schema_properties)
645
+ end
646
+
647
+ def full_rspec_description
648
+ with_rspec_examples ? SwaggerAutogenerate::SwaggerTrace.rspec_description : nil
649
+ end
650
+
651
+ class << self
652
+ attr_accessor :rspec_description
653
+ end
491
654
  end
492
655
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SwaggerAutogenerate
4
- VERSION = "1.1.1"
4
+ VERSION = "1.2.0"
5
5
  end
@@ -8,14 +8,24 @@ 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_path_environment_variable].present? || ENV[SwaggerTrace.generate_swagger_environment_variable].present?) &&
19
+ Rails.env.send("#{SwaggerTrace.environment_name.to_s}?")
20
+ end
16
21
  end
17
22
 
18
- # fix []
19
- # create command to direct add configuration file in test environment
20
- # handel headers
21
- # can the SWAGGER accespt empty value?
23
+ if defined?(RSpec) && SwaggerAutogenerate.allow_swagger?
24
+ require 'rspec/rails'
25
+
26
+ RSpec.configure do |config|
27
+ config.before(:each) do |example|
28
+ SwaggerAutogenerate::SwaggerTrace.rspec_description = SwaggerAutogenerate.extract_description(example.metadata[:full_description])
29
+ end
30
+ end
31
+ 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.1
4
+ version: 1.2.0
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-27 00:00:00.000000000 Z
11
+ date: 2024-09-08 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