rspec-openapi 0.10.0 → 0.11.0

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: 9749f7a6121a78737336bd436f5fda8b20381a82f4cb507f42667bf3d38a2a4b
4
- data.tar.gz: ff0bc4a559323f1285d282ab786b5666c950b8ad0b9585fa749cf1f2b0f3613e
3
+ metadata.gz: 0a48ebba5d2201f35bb94f47d5bd649444bb9c58ae1f0ef91f57e315553f9ef2
4
+ data.tar.gz: 71d4dec68449c2e14b4d3ce7058622b7c56629bee2814e04b1f16e5e817a7bf2
5
5
  SHA512:
6
- metadata.gz: 4e412c58158ffaa1518640e3082ef04c41d50ec43de94ef032c866ebbec2468775d4ea3b2c976294f14ce6b8570b3e86df7248f17877c491efa9fc31e5a8819a
7
- data.tar.gz: 65d7308f7d552d9ac299a6d3330933283c237345b477de260a2e2af24210268f2e41350619cec83f145f028a7374b197281cbd9752d1cb2aa3baa696f8240739
6
+ metadata.gz: 4c984f5dbd1a4587a9d34686c50e06a832051215f5e22abc8a96781ecebe57e0bdddabeef093db06f5bea23f58e70322a7574168f621e8765721ab2c2cf19c48
7
+ data.tar.gz: 2877daab4753106d04275e3189b8a8e648b7268a6c6d7e422e94d5bfb230064a2e875e73531abe6930bfa6c8b7cdefe7d06ee512cdcb4e22adb618915349514b
@@ -28,12 +28,12 @@ jobs:
28
28
  uses: actions/checkout@v4
29
29
 
30
30
  - name: Initialize CodeQL
31
- uses: github/codeql-action/init@v2
31
+ uses: github/codeql-action/init@v3
32
32
  with:
33
33
  languages: ${{ matrix.language }}
34
34
 
35
35
  - name: Autobuild
36
- uses: github/codeql-action/autobuild@v2
36
+ uses: github/codeql-action/autobuild@v3
37
37
 
38
38
  - name: Perform CodeQL Analysis
39
- uses: github/codeql-action/analyze@v2
39
+ uses: github/codeql-action/analyze@v3
@@ -30,6 +30,6 @@ jobs:
30
30
  "
31
31
 
32
32
  - name: Upload Sarif output
33
- uses: github/codeql-action/upload-sarif@v2
33
+ uses: github/codeql-action/upload-sarif@v3
34
34
  with:
35
35
  sarif_file: rubocop.sarif
@@ -26,6 +26,8 @@ jobs:
26
26
  rails: 6.1.6
27
27
  - ruby: ruby:3.1
28
28
  rails: 7.0.3
29
+ - ruby: ruby:3.3
30
+ rails: 7.1.2
29
31
  coverage: coverage
30
32
  env:
31
33
  RAILS_VERSION: ${{ matrix.rails == '' && '6.1.6' || matrix.rails }}
data/.rubocop_todo.yml CHANGED
@@ -1,25 +1,35 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2023-04-14 06:22:29 UTC using RuboCop version 1.49.0.
3
+ # on 2024-01-13 11:12:43 UTC using RuboCop version 1.50.2.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
- # Offense count: 10
9
+ # Offense count: 9
10
10
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
11
11
  Metrics/AbcSize:
12
- Max: 31
12
+ Max: 48
13
+
14
+ # Offense count: 2
15
+ # Configuration parameters: CountComments, CountAsOne.
16
+ Metrics/ClassLength:
17
+ Max: 192
13
18
 
14
- # Offense count: 4
19
+ # Offense count: 5
15
20
  # Configuration parameters: AllowedMethods, AllowedPatterns.
16
21
  Metrics/CyclomaticComplexity:
17
- Max: 10
22
+ Max: 13
18
23
 
19
- # Offense count: 13
24
+ # Offense count: 16
20
25
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
21
26
  Metrics/MethodLength:
22
- Max: 30
27
+ Max: 31
28
+
29
+ # Offense count: 1
30
+ # Configuration parameters: AllowedMethods, AllowedPatterns.
31
+ Metrics/PerceivedComplexity:
32
+ Max: 13
23
33
 
24
34
  # Offense count: 1
25
35
  # Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers, AllowedPatterns.
@@ -29,7 +39,7 @@ Naming/VariableNumber:
29
39
  Exclude:
30
40
  - 'spec/integration_tests/roda_test.rb'
31
41
 
32
- # Offense count: 5
42
+ # Offense count: 6
33
43
  # Configuration parameters: AllowedConstants.
34
44
  Style/Documentation:
35
45
  Exclude:
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+ ## v0.11.0
2
+
3
+ ## What's Changed
4
+ - feat: Allow path-based config overrides
5
+ [#162](https://github.com/exoego/rspec-openapi/pull/162)
6
+ - enhancement: Sort HTTP methods, response status codes, and contents lexicographically
7
+ [#163](https://github.com/exoego/rspec-openapi/pull/163)
8
+ - enhancement: Remove parameters that conflict with security schemas
9
+ [#166](https://github.com/exoego/rspec-openapi/pull/166)
10
+
1
11
  ## v0.10.0
2
12
  - bugfix: Merge parameter data to preserve description in manually edited Openapi spec
3
13
  [#149](https://github.com/exoego/rspec-openapi/pull/149)
@@ -7,26 +7,33 @@ class RSpec::OpenAPI::ResultRecorder
7
7
  end
8
8
 
9
9
  def record_results!
10
- title = RSpec::OpenAPI.title
11
10
  @path_records.each do |path, records|
11
+ # Look for a path-specific config file and run it.
12
+ config_file = File.join(File.dirname(path), RSpec::OpenAPI.config_filename)
13
+ begin
14
+ require config_file if File.exist?(config_file)
15
+ rescue StandardError => e
16
+ puts "WARNING: Unable to load #{config_file}: #{e}"
17
+ end
18
+
19
+ title = RSpec::OpenAPI.title
12
20
  RSpec::OpenAPI::SchemaFile.new(path).edit do |spec|
13
21
  schema = RSpec::OpenAPI::DefaultSchema.build(title)
14
22
  schema[:info].merge!(RSpec::OpenAPI.info)
15
23
  RSpec::OpenAPI::SchemaMerger.merge!(spec, schema)
16
24
  new_from_zero = {}
17
25
  records.each do |record|
18
- begin
19
- record_schema = RSpec::OpenAPI::SchemaBuilder.build(record)
20
- RSpec::OpenAPI::SchemaMerger.merge!(spec, record_schema)
21
- RSpec::OpenAPI::SchemaMerger.merge!(new_from_zero, record_schema)
22
- rescue StandardError, NotImplementedError => e # e.g. SchemaBuilder raises a NotImplementedError
23
- @error_records[e] = record # Avoid failing the build
24
- end
26
+ record_schema = RSpec::OpenAPI::SchemaBuilder.build(record)
27
+ RSpec::OpenAPI::SchemaMerger.merge!(spec, record_schema)
28
+ RSpec::OpenAPI::SchemaMerger.merge!(new_from_zero, record_schema)
29
+ rescue StandardError, NotImplementedError => e # e.g. SchemaBuilder raises a NotImplementedError
30
+ @error_records[e] = record # Avoid failing the build
25
31
  end
32
+ RSpec::OpenAPI::SchemaCleaner.cleanup_conflicting_security_parameters!(spec)
26
33
  RSpec::OpenAPI::SchemaCleaner.cleanup!(spec, new_from_zero)
27
34
  RSpec::OpenAPI::ComponentsUpdater.update!(spec, new_from_zero)
28
35
  RSpec::OpenAPI::SchemaCleaner.cleanup_empty_required_array!(spec)
29
- RSpec::OpenAPI::SchemaCleaner.sort_paths!(spec)
36
+ RSpec::OpenAPI::SchemaSorter.deep_sort!(spec)
30
37
  end
31
38
  end
32
39
  end
@@ -39,6 +39,24 @@ class << RSpec::OpenAPI::SchemaCleaner = Object.new
39
39
  base
40
40
  end
41
41
 
42
+ def cleanup_conflicting_security_parameters!(base)
43
+ security_schemes = base.dig('components', 'securitySchemes') || {}
44
+
45
+ return if security_schemes.empty?
46
+
47
+ paths_to_security_definitions = RSpec::OpenAPI::HashHelper.matched_paths_deeply_nested(base, 'paths', 'security')
48
+
49
+ paths_to_security_definitions.each do |path|
50
+ parent_path_definition = base.dig(*path.take(path.length - 1))
51
+
52
+ security_schemes.each do |security_scheme_name, security_scheme|
53
+ remove_parameters_conflicting_with_security_sceheme!(
54
+ parent_path_definition, security_scheme, security_scheme_name,
55
+ )
56
+ end
57
+ end
58
+ end
59
+
42
60
  def cleanup_empty_required_array!(base)
43
61
  paths_to_objects = [
44
62
  *RSpec::OpenAPI::HashHelper.matched_paths_deeply_nested(base, 'components.schemas', 'properties'),
@@ -51,15 +69,20 @@ class << RSpec::OpenAPI::SchemaCleaner = Object.new
51
69
  end
52
70
  end
53
71
 
54
- # Sort "paths" lexicographically to make the order more predictable
55
- #
56
- # @param [Hash] #
57
- def sort_paths!(spec)
58
- spec['paths'] = spec['paths']&.entries&.sort_by! { |path, _| path }.to_h
59
- end
60
-
61
72
  private
62
73
 
74
+ def remove_parameters_conflicting_with_security_sceheme!(path_definition, security_scheme, security_scheme_name)
75
+ return unless path_definition['security']
76
+ return unless path_definition['parameters']
77
+ return unless path_definition.dig('security', 0).keys.include?(security_scheme_name)
78
+
79
+ path_definition['parameters'].reject! do |parameter|
80
+ parameter['in'] == security_scheme['in'] && # same location (ie. header)
81
+ parameter['name'] == security_scheme['name'] # same name (ie. AUTHORIZATION)
82
+ end
83
+ path_definition.delete('parameters') if path_definition['parameters'].empty?
84
+ end
85
+
63
86
  def cleanup_array!(base, spec, selector, fields_for_identity = [])
64
87
  marshal = lambda do |obj|
65
88
  Marshal.dump(slice(obj, fields_for_identity))
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ class << RSpec::OpenAPI::SchemaSorter = Object.new
4
+ # Sort some unpredictably ordered properties in a lexicographical manner to make the order more predictable.
5
+ #
6
+ # @param [Hash|Array]
7
+ def deep_sort!(spec)
8
+ # paths
9
+ deep_sort_by_selector!(spec, 'paths')
10
+
11
+ # methods
12
+ deep_sort_by_selector!(spec, 'paths.*')
13
+
14
+ # response status code
15
+ deep_sort_by_selector!(spec, 'paths.*.*.responses')
16
+
17
+ # content-type
18
+ deep_sort_by_selector!(spec, 'paths.*.*.responses.*.content')
19
+ end
20
+
21
+ private
22
+
23
+ # @param [Hash] base
24
+ # @param [String] selector
25
+ def deep_sort_by_selector!(base, selector)
26
+ RSpec::OpenAPI::HashHelper.matched_paths(base, selector).each do |paths|
27
+ deep_sort_hash!(base.dig(*paths))
28
+ end
29
+ end
30
+
31
+ def deep_sort_hash!(hash)
32
+ sorted = hash.entries.sort_by { |k, _| k }.to_h
33
+ hash.replace(sorted)
34
+ end
35
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RSpec
4
4
  module OpenAPI
5
- VERSION = '0.10.0'
5
+ VERSION = '0.11.0'
6
6
  end
7
7
  end
data/lib/rspec/openapi.rb CHANGED
@@ -9,6 +9,7 @@ require 'rspec/openapi/schema_builder'
9
9
  require 'rspec/openapi/schema_file'
10
10
  require 'rspec/openapi/schema_merger'
11
11
  require 'rspec/openapi/schema_cleaner'
12
+ require 'rspec/openapi/schema_sorter'
12
13
 
13
14
  require 'rspec/openapi/minitest_hooks' if Object.const_defined?('Minitest')
14
15
  require 'rspec/openapi/rspec_hooks' if ENV['OPENAPI'] && Object.const_defined?('RSpec')
@@ -31,6 +32,9 @@ module RSpec::OpenAPI
31
32
  @path_records = Hash.new { |h, k| h[k] = [] }
32
33
  @ignored_path_params = %i[controller action format]
33
34
 
35
+ # This is the configuraion override file name we look for within each path.
36
+ @config_filename = 'rspec_openapi.rb'
37
+
34
38
  class << self
35
39
  attr_accessor :path,
36
40
  :title,
@@ -48,5 +52,7 @@ module RSpec::OpenAPI
48
52
  :response_headers,
49
53
  :path_records,
50
54
  :ignored_path_params
55
+
56
+ attr_reader :config_filename
51
57
  end
52
58
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-openapi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Takashi Kokubun
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2023-12-11 00:00:00.000000000 Z
12
+ date: 2024-01-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: actionpack
@@ -76,6 +76,7 @@ files:
76
76
  - lib/rspec/openapi/schema_cleaner.rb
77
77
  - lib/rspec/openapi/schema_file.rb
78
78
  - lib/rspec/openapi/schema_merger.rb
79
+ - lib/rspec/openapi/schema_sorter.rb
79
80
  - lib/rspec/openapi/version.rb
80
81
  - rspec-openapi.gemspec
81
82
  - scripts/rspec