swagger_autogenerate 1.1.1 → 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +1 -0
- data/Gemfile.lock +1 -1
- data/lib/swagger_autogenerate/configuration.rb +8 -1
- data/lib/swagger_autogenerate/swagger_trace.rb +175 -25
- data/lib/swagger_autogenerate/version.rb +1 -1
- data/lib/swagger_autogenerate.rb +14 -5
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fa0e0d56334a728cbd835bf8ecf0cf4b2c330eb62aeb92e6b9bc20d1251ed5cd
|
4
|
+
data.tar.gz: c5869ad74ec90bffdb1a58bdfbb52645849b14f88e81e876f5b856d280dab536
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7766553dbaa81ee1506f36727411a24e36d9dd7c73bc4733a2bc034be406b2c94e4526f7c73467e1d383cf3e566fecaa6ea592a06627f4a5778dba61cd5f142e
|
7
|
+
data.tar.gz: ab857ce41cc465f94b961c61d2f3bbeb48195c8bf5472152c43524384caa57313325b852df8417e2c07489fed8ae0e656c941d9c91a395ea6e16895ace7a990c
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,12 +1,14 @@
|
|
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'
|
@@ -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
|
-
@
|
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, :
|
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,17 +216,24 @@ 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
|
-
|
221
|
-
|
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
|
@@ -230,6 +244,8 @@ module SwaggerAutogenerate
|
|
230
244
|
data.map do |key, value|
|
231
245
|
if value.is_a?(Hash)
|
232
246
|
hash_data.merge!({ key => value })
|
247
|
+
elsif value.is_a?(Array)
|
248
|
+
value.each_with_index { |v, index| convert_to_multipart(v, key) }
|
233
249
|
else
|
234
250
|
payload_hash.merge!({ key => { 'type' => schema_type(value), 'example' => example(value) } })
|
235
251
|
end
|
@@ -250,10 +266,93 @@ module SwaggerAutogenerate
|
|
250
266
|
}
|
251
267
|
end
|
252
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
|
+
|
253
352
|
def content_body(data)
|
254
353
|
hash = {}
|
255
354
|
# hash.merge!(content_json(data))
|
256
|
-
hash.merge!(
|
355
|
+
hash.merge!(json_to_content_form_data(data))
|
257
356
|
|
258
357
|
{ 'content' => hash }
|
259
358
|
end
|
@@ -351,19 +450,18 @@ module SwaggerAutogenerate
|
|
351
450
|
end
|
352
451
|
|
353
452
|
def content_json_example(data)
|
354
|
-
|
453
|
+
example_title = full_rspec_description.present? ? full_rspec_description : 'example-0'
|
454
|
+
|
455
|
+
{
|
355
456
|
'application/json' => {
|
356
457
|
'schema' => { 'type' => 'object' },
|
357
458
|
'examples' => {
|
358
|
-
|
459
|
+
example_title => {
|
359
460
|
'value' => data
|
360
461
|
}
|
361
462
|
}
|
362
463
|
}
|
363
464
|
}
|
364
|
-
hash['application/json']['examples']['example-0']['description'] = "payload => #{example_description}" if with_example_description && !example_description.empty?
|
365
|
-
|
366
|
-
hash
|
367
465
|
end
|
368
466
|
|
369
467
|
def example_description
|
@@ -396,20 +494,48 @@ module SwaggerAutogenerate
|
|
396
494
|
@payload_hash ||= {}
|
397
495
|
end
|
398
496
|
|
399
|
-
def new_example
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
last_example =
|
405
|
-
last_example
|
406
|
-
|
407
|
-
|
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])
|
408
506
|
end
|
409
507
|
|
410
508
|
true
|
411
509
|
end
|
412
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
|
+
|
413
539
|
def apply_yaml_file_changes
|
414
540
|
(check_path || check_method || check_status) &&
|
415
541
|
(check_parameters || check_parameter) &&
|
@@ -438,24 +564,29 @@ module SwaggerAutogenerate
|
|
438
564
|
def check_path
|
439
565
|
unless old_paths.key?(current_path)
|
440
566
|
yaml_file['paths'].merge!({ current_path => paths[current_path] })
|
567
|
+
update_example_title(true)
|
441
568
|
end
|
442
569
|
end
|
443
570
|
|
444
571
|
def check_method
|
445
572
|
unless old_paths[current_path].key?(request.method.downcase)
|
446
573
|
yaml_file['paths'][current_path][request.method.downcase] = { 'responses' => swagger_response }
|
574
|
+
update_example_title(true)
|
447
575
|
end
|
448
576
|
end
|
449
577
|
|
450
578
|
def check_status
|
579
|
+
example_title = full_rspec_description.present? ? full_rspec_description : 'example-0'
|
451
580
|
if old_paths[current_path][request.method.downcase]['responses'].present?
|
452
581
|
if old_paths[current_path][request.method.downcase]['responses']&.key?(response.status.to_s)
|
453
|
-
|
582
|
+
update_example_title
|
454
583
|
else
|
455
584
|
yaml_file['paths'][current_path][request.method.downcase]['responses'].merge!(swagger_response)
|
585
|
+
update_example_title(true)
|
456
586
|
end
|
457
587
|
else
|
458
588
|
yaml_file['paths'][current_path][request.method.downcase]['responses'] = swagger_response
|
589
|
+
update_example_title
|
459
590
|
end
|
460
591
|
end
|
461
592
|
|
@@ -481,12 +612,31 @@ module SwaggerAutogenerate
|
|
481
612
|
|
482
613
|
def check_request_body
|
483
614
|
if paths[current_path][request.method.downcase]['requestBody'].present?
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
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
|
488
623
|
end
|
489
624
|
end
|
490
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
|
491
641
|
end
|
492
642
|
end
|
data/lib/swagger_autogenerate.rb
CHANGED
@@ -8,14 +8,23 @@ module SwaggerAutogenerate
|
|
8
8
|
def process_action(*args)
|
9
9
|
super
|
10
10
|
|
11
|
-
if
|
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
|
16
20
|
end
|
17
21
|
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
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.
|
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-
|
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
|