rspec-openapi 0.9.0 → 0.10.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: d55c7178770a58a980d06669adfab735ba84b51a283302dd8e14e91af4b7b4e9
4
- data.tar.gz: 7b0030924262f8a1cd7027df612315b8d6e3fb89e91f9b4e57c3ec83f7e9bfd6
3
+ metadata.gz: 9749f7a6121a78737336bd436f5fda8b20381a82f4cb507f42667bf3d38a2a4b
4
+ data.tar.gz: ff0bc4a559323f1285d282ab786b5666c950b8ad0b9585fa749cf1f2b0f3613e
5
5
  SHA512:
6
- metadata.gz: 4cf846ca12d2062ae17c0b5d1829a7887c206425330c015f5fdde310c59678cb802b4cadb60f63c1ca6d55063c3d4f1cc2ac7813db10c6d8611a0fa3af975192
7
- data.tar.gz: 7501fac5fbfd8b0c4cec6cb196feb9ff09a640c4aff7165a93a6880eebea194d5c30674eefadb53987538ebed913d8d43ab625f1a7c8a3a12ad76ba15b459687
6
+ metadata.gz: 4e412c58158ffaa1518640e3082ef04c41d50ec43de94ef032c866ebbec2468775d4ea3b2c976294f14ce6b8570b3e86df7248f17877c491efa9fc31e5a8819a
7
+ data.tar.gz: 65d7308f7d552d9ac299a6d3330933283c237345b477de260a2e2af24210268f2e41350619cec83f145f028a7374b197281cbd9752d1cb2aa3baa696f8240739
@@ -0,0 +1,8 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "github-actions"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "monthly"
7
+ labels:
8
+ - "chore"
@@ -25,7 +25,7 @@ jobs:
25
25
 
26
26
  steps:
27
27
  - name: Checkout repository
28
- uses: actions/checkout@v3
28
+ uses: actions/checkout@v4
29
29
 
30
30
  - name: Initialize CodeQL
31
31
  uses: github/codeql-action/init@v2
@@ -14,7 +14,7 @@ jobs:
14
14
 
15
15
  steps:
16
16
  - name: Checkout repository
17
- uses: actions/checkout@v3
17
+ uses: actions/checkout@v4
18
18
 
19
19
  - name: Set up Ruby
20
20
  uses: ruby/setup-ruby@v1
@@ -31,9 +31,14 @@ jobs:
31
31
  RAILS_VERSION: ${{ matrix.rails == '' && '6.1.6' || matrix.rails }}
32
32
  COVERAGE: ${{ matrix.coverage || '' }}
33
33
  steps:
34
- - uses: actions/checkout@v2
34
+ - uses: actions/checkout@v4
35
35
  - name: bundle install
36
36
  run: bundle install -j$(nproc) --retry 3
37
+ - name: install simplecov-fork only for minitest with coverage
38
+ run: |
39
+ gem install specific_install
40
+ gem specific_install https://github.com/exoego/simplecov.git branch-fix
41
+ if: matrix.coverage == 'coverage'
37
42
  - run: bundle exec rspec
38
43
  timeout-minutes: 1
39
44
  - name: Upload coverage reports
data/.simplecov_spawn.rb CHANGED
@@ -9,6 +9,7 @@ unless ENV['COVERAGE'] && ENV['COVERAGE'].empty?
9
9
  SimpleCov::Formatter::CoberturaFormatter,
10
10
  ])
11
11
  SimpleCov.start do
12
+ enable_coverage :branch
12
13
  add_filter '/spec/'
13
14
  add_filter '/scripts/'
14
15
  end
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## v0.10.0
2
+ - bugfix: Merge parameter data to preserve description in manually edited Openapi spec
3
+ [#149](https://github.com/exoego/rspec-openapi/pull/149)
4
+ - feat: Add ability to configure which path params to ignore
5
+ [#150](https://github.com/exoego/rspec-openapi/pull/150)
6
+ - feat: Add custom title
7
+ [#147](https://github.com/exoego/rspec-openapi/pull/147)
8
+ - feat: Add ability to define custom summary and tags builders
9
+ [#148](https://github.com/exoego/rspec-openapi/pull/148)
10
+ - enhancement: Sort paths lexicographically so the order of paths is more stable and predictable
11
+ [#155](https://github.com/exoego/rspec-openapi/pull/155)
12
+ - enhancement: requestBody should not merge requestBody from error examples
13
+ [#154](https://github.com/exoego/rspec-openapi/pull/154)
14
+
1
15
  ## v0.9.0
2
16
  - bugfix: Fix engine path resolution
3
17
  [#113](https://github.com/exoego/rspec-openapi/pull/113)
data/Gemfile CHANGED
@@ -10,7 +10,7 @@ gem 'roda'
10
10
  gem 'rspec-rails'
11
11
 
12
12
  group :test do
13
- gem 'simplecov'
13
+ gem 'simplecov', git: 'https://github.com/exoego/simplecov.git', branch: 'branch-fix'
14
14
  gem 'simplecov-cobertura'
15
15
  gem 'super_diff'
16
16
  end
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # rspec-openapi ![test](https://github.com/exoego/rspec-openapi/workflows/test/badge.svg) [![codecov](https://codecov.io/gh/exoego/rspec-openapi/branch/master/graph/badge.svg?token=egYm6AlxkD)](https://codecov.io/gh/exoego/rspec-openapi)
1
+ # rspec-openapi [![Gem Version](https://badge.fury.io/rb/rspec-openapi.svg)](https://badge.fury.io/rb/rspec-openapi) [![test](https://github.com/exoego/rspec-openapi/actions/workflows/test.yml/badge.svg)](https://github.com/exoego/rspec-openapi/actions/workflows/test.yml) [![codecov](https://codecov.io/gh/exoego/rspec-openapi/branch/master/graph/badge.svg?token=egYm6AlxkD)](https://codecov.io/gh/exoego/rspec-openapi)
2
2
 
3
3
  Generate OpenAPI schema from RSpec request specs.
4
4
 
@@ -122,6 +122,8 @@ RSpec::OpenAPI.path = -> (example) {
122
122
  end
123
123
  }
124
124
 
125
+ RSpec::OpenAPI.title = 'OpenAPI Documentation'
126
+
125
127
  # Disable generating `example`
126
128
  RSpec::OpenAPI.enable_example = false
127
129
 
@@ -167,8 +169,21 @@ EOS
167
169
  # Generate a custom description, given an RSpec example
168
170
  RSpec::OpenAPI.description_builder = -> (example) { example.description }
169
171
 
172
+ # Generate a custom summary, given an RSpec example
173
+ # This example uses the summary from the example_group.
174
+ RSpec::OpenAPI.summary_builder = ->(example) { example.metadata.dig(:example_group, :openapi, :summary) }
175
+
176
+ # Generate a custom tags, given an RSpec example
177
+ # This example uses the tags from the parent_example_group
178
+ RSpec::OpenAPI.tags_builder = -> (example) { example.metadata.dig(:example_group, :parent_example_group, :openapi, :tags) }
179
+
170
180
  # Change the example type(s) that will generate schema
171
181
  RSpec::OpenAPI.example_types = %i[request]
182
+
183
+ # Configure which path params to ignore
184
+ # :controller and :action always exist. :format is added when routes is configured as such.
185
+ RSpec::OpenAPI.ignored_path_params = %i[controller action format]
186
+
172
187
  ```
173
188
 
174
189
  ### Can I use rspec-openapi with `$ref` to minimize duplication of schema?
@@ -199,7 +214,7 @@ paths:
199
214
  application/json:
200
215
  schema:
201
216
  $ref: "#/components/schemas/User"
202
- # Note) #/components/schamas is not needed to be defined.
217
+ # Note) #/components/schemas is not needed to be defined.
203
218
  ```
204
219
 
205
220
  3. Then, re-run rspec-openapi. It will generate `#/components/schemas` with the referenced schema (`User` for example) newly-generated or updated.
@@ -278,7 +293,7 @@ If you find a room for improvement, open an issue.
278
293
 
279
294
  ### How can I add information which can't be generated from RSpec?
280
295
 
281
- rspec-openapi tries to keep manual modifications as much as possible when generating specs.
296
+ rspec-openapi tries to preserve manual modifications as much as possible when generating specs.
282
297
  You can directly edit `doc/openapi.yaml` as you like without spoiling the automatic generation capability.
283
298
 
284
299
  ### Can I exclude specific specs from OpenAPI generation?
@@ -62,8 +62,8 @@ class << RSpec::OpenAPI::RecordBuilder = Object.new
62
62
 
63
63
  def extract_request_attributes(request, example)
64
64
  metadata = example.metadata[:openapi] || {}
65
- summary = metadata[:summary]
66
- tags = metadata[:tags]
65
+ summary = metadata[:summary] || RSpec::OpenAPI.summary_builder.call(example)
66
+ tags = metadata[:tags] || RSpec::OpenAPI.tags_builder.call(example)
67
67
  operation_id = metadata[:operation_id]
68
68
  required_request_params = metadata[:required_request_params] || []
69
69
  security = metadata[:security]
@@ -83,7 +83,7 @@ class << RSpec::OpenAPI::RecordBuilder = Object.new
83
83
  tags ||= [route.requirements[:controller]&.classify].compact
84
84
  # :controller and :action always exist. :format is added when routes is configured as such.
85
85
  # TODO: Use .except(:controller, :action, :format) when we drop support for Ruby 2.x
86
- raw_path_params = raw_path_params.slice(*(raw_path_params.keys - %i[controller action format]))
86
+ raw_path_params = raw_path_params.slice(*(raw_path_params.keys - RSpec::OpenAPI.ignored_path_params))
87
87
  end
88
88
  summary ||= "#{request.method} #{path}"
89
89
  [path, summary, tags, operation_id, required_request_params, raw_path_params, description, security]
@@ -7,7 +7,7 @@ class RSpec::OpenAPI::ResultRecorder
7
7
  end
8
8
 
9
9
  def record_results!
10
- title = File.basename(Dir.pwd)
10
+ title = RSpec::OpenAPI.title
11
11
  @path_records.each do |path, records|
12
12
  RSpec::OpenAPI::SchemaFile.new(path).edit do |spec|
13
13
  schema = RSpec::OpenAPI::DefaultSchema.build(title)
@@ -26,6 +26,7 @@ class RSpec::OpenAPI::ResultRecorder
26
26
  RSpec::OpenAPI::SchemaCleaner.cleanup!(spec, new_from_zero)
27
27
  RSpec::OpenAPI::ComponentsUpdater.update!(spec, new_from_zero)
28
28
  RSpec::OpenAPI::SchemaCleaner.cleanup_empty_required_array!(spec)
29
+ RSpec::OpenAPI::SchemaCleaner.sort_paths!(spec)
29
30
  end
30
31
  end
31
32
  end
@@ -120,6 +120,7 @@ class << RSpec::OpenAPI::SchemaBuilder = Object.new
120
120
  def build_request_body(record)
121
121
  return nil if record.request_content_type.nil?
122
122
  return nil if record.request_params.empty?
123
+ return nil if record.status >= 400
123
124
 
124
125
  {
125
126
  content: {
@@ -51,6 +51,13 @@ class << RSpec::OpenAPI::SchemaCleaner = Object.new
51
51
  end
52
52
  end
53
53
 
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
+
54
61
  private
55
62
 
56
63
  def cleanup_array!(base, spec, selector, fields_for_identity = [])
@@ -43,16 +43,28 @@ class << RSpec::OpenAPI::SchemaMerger = Object.new
43
43
  end
44
44
 
45
45
  def merge_arrays(base, key, value)
46
- case key
47
- when 'parameters'
48
- base[key] = value | base[key]
49
- base[key].uniq! { |param| param.slice('name', 'in') }
50
- when 'required'
51
- # Preserve properties that appears in all test cases
52
- base[key] = value & base[key]
53
- else
54
- # last one wins
55
- base[key] = value
46
+ base[key] = case key
47
+ when 'parameters'
48
+ merge_parameters(base, key, value)
49
+ when 'required'
50
+ # Preserve properties that appears in all test cases
51
+ value & base[key]
52
+ else
53
+ # last one wins
54
+ value
55
+ end
56
+ end
57
+
58
+ def merge_parameters(base, key, value)
59
+ all_parameters = value | base[key]
60
+
61
+ unique_base_parameters = base[key].index_by { |parameter| [parameter['name'], parameter['in']] }
62
+ all_parameters = all_parameters.map do |parameter|
63
+ base_parameter = unique_base_parameters[[parameter['name'], parameter['in']]] || {}
64
+ base_parameter ? base_parameter.merge(parameter) : parameter
56
65
  end
66
+
67
+ all_parameters.uniq! { |param| param.slice('name', 'in') }
68
+ base[key] = all_parameters
57
69
  end
58
70
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RSpec
4
4
  module OpenAPI
5
- VERSION = '0.9.0'
5
+ VERSION = '0.10.0'
6
6
  end
7
7
  end
data/lib/rspec/openapi.rb CHANGED
@@ -15,9 +15,12 @@ require 'rspec/openapi/rspec_hooks' if ENV['OPENAPI'] && Object.const_defined?('
15
15
 
16
16
  module RSpec::OpenAPI
17
17
  @path = 'doc/openapi.yaml'
18
+ @title = File.basename(Dir.pwd)
18
19
  @comment = nil
19
20
  @enable_example = true
20
21
  @description_builder = ->(example) { example.description }
22
+ @summary_builder = ->(example) { example.metadata[:summary] }
23
+ @tags_builder = ->(example) { example.metadata[:tags] }
21
24
  @info = {}
22
25
  @application_version = '1.0.0'
23
26
  @request_headers = []
@@ -26,12 +29,16 @@ module RSpec::OpenAPI
26
29
  @example_types = %i[request]
27
30
  @response_headers = []
28
31
  @path_records = Hash.new { |h, k| h[k] = [] }
32
+ @ignored_path_params = %i[controller action format]
29
33
 
30
34
  class << self
31
35
  attr_accessor :path,
36
+ :title,
32
37
  :comment,
33
38
  :enable_example,
34
39
  :description_builder,
40
+ :summary_builder,
41
+ :tags_builder,
35
42
  :info,
36
43
  :application_version,
37
44
  :request_headers,
@@ -39,6 +46,7 @@ module RSpec::OpenAPI
39
46
  :security_schemes,
40
47
  :example_types,
41
48
  :response_headers,
42
- :path_records
49
+ :path_records,
50
+ :ignored_path_params
43
51
  end
44
52
  end
@@ -36,8 +36,7 @@ begin
36
36
  require 'simplecov'
37
37
 
38
38
  SimpleCov.start do
39
- # Flaky :(
40
- # enable_coverage :branch
39
+ enable_coverage :branch
41
40
  end
42
41
  end
43
42
  rescue LoadError
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.9.0
4
+ version: 0.10.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-10-10 00:00:00.000000000 Z
12
+ date: 2023-12-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: actionpack
@@ -47,6 +47,7 @@ executables: []
47
47
  extensions: []
48
48
  extra_rdoc_files: []
49
49
  files:
50
+ - ".github/dependabot.yml"
50
51
  - ".github/workflows/codeql-analysis.yml"
51
52
  - ".github/workflows/rubocop.yml"
52
53
  - ".github/workflows/test.yml"