rspec-openapi 0.21.1 → 0.21.3

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: fcdab2071b77e7d4df6910839d60df6d3493fcf3bc10c47829fc0609451c5094
4
- data.tar.gz: 0efb97d546a285eaa1108dbec9b9dd6598a119b93f46dde04e070cdaf8f029d3
3
+ metadata.gz: d28b278fc0d9e8f0ce356103ea53e7b97392eac4f7c09fda493a9d7b1e2bfa10
4
+ data.tar.gz: 501c53f68a84d09f96f40a0e0749d65b2ceba13d16ebeb4819c989fdd7f62c2e
5
5
  SHA512:
6
- metadata.gz: cb16c77c27f8a766cb5e09bce79d2ef7af160277b274dbd75785f8ca9466e28e6800f498f167644fb16e66b4f6a1dc7becd77b0632d4c1a717b49739e4ed014c
7
- data.tar.gz: efa94d5ea193fd56f3ac3b4f220453c3ceb184596688422fff7fe9e14223a44c5427ad17206a7cd4014e16f8e1f4bafc3f3ebdce3a336251a036f5daee83ee2e
6
+ metadata.gz: 7e4636d3f30bb1114932aabdb6ae2ef40bb9492a08d5d7c9022f52d8b5e4a415e424abc8611a14a8f7f6d8c139947ee900bc50cdfafda19e95bcd6cb06d26142
7
+ data.tar.gz: 8a3e455ed8a022f5e9df443a14f3159665b77ca4a416b6b3f29404efd367717060f7121fd1a3ec77190d1bc426850b58faf2cc6092c7acc9c18e8f78e732aeb7
@@ -25,7 +25,7 @@ jobs:
25
25
 
26
26
  steps:
27
27
  - name: Checkout repository
28
- uses: actions/checkout@v5
28
+ uses: actions/checkout@v6
29
29
 
30
30
  - name: Initialize CodeQL
31
31
  uses: github/codeql-action/init@v4
@@ -0,0 +1,79 @@
1
+ name: prepare release
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ version:
7
+ description: 'Version to release (e.g. 0.21.3 or v0.21.3)'
8
+ required: true
9
+
10
+ jobs:
11
+ push:
12
+ name: Prepare release PR
13
+ runs-on: ubuntu-latest
14
+
15
+ permissions:
16
+ id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
17
+ contents: write # required to push release branch and open PR
18
+ pull-requests: write # required to create the release PR with GITHUB_TOKEN
19
+
20
+ steps:
21
+ - uses: actions/checkout@v5
22
+ with:
23
+ fetch-depth: 0
24
+
25
+ - name: Bump version.rb
26
+ run: |
27
+ set -euo pipefail
28
+ version="${{ github.event.inputs.version }}"
29
+ version="${version#v}"
30
+
31
+ echo "VERSION_NO_V=$version" >> "$GITHUB_ENV"
32
+ echo "VERSION_TAG=v$version" >> "$GITHUB_ENV"
33
+
34
+ current_version=$(ruby -e "require_relative './lib/rspec/openapi/version'; puts RSpec::OpenAPI::VERSION")
35
+ VERSION_NO_V="$version" CURRENT_VERSION="$current_version" ruby - <<'RUBY'
36
+ version = ENV.fetch('VERSION_NO_V')
37
+ unless version.match?(/\A\d+(?:\.\d+)*\z/)
38
+ warn "Invalid version format: #{version}"
39
+ exit 1
40
+ end
41
+
42
+ require 'rubygems'
43
+ new_version = Gem::Version.new(version)
44
+ current_version = Gem::Version.new(ENV.fetch('CURRENT_VERSION'))
45
+ if new_version <= current_version
46
+ warn "Given version (#{new_version}) must be newer than current version (#{current_version})"
47
+ exit 1
48
+ end
49
+ RUBY
50
+
51
+ ruby -pi -e "sub(/VERSION = .*/, \"VERSION = '$version'\")" lib/rspec/openapi/version.rb
52
+ git status --short
53
+
54
+ - name: Commit version bump
55
+ run: |
56
+ set -euo pipefail
57
+ version="$VERSION_NO_V"
58
+
59
+ release_branch="release/v${version}"
60
+ echo "RELEASE_BRANCH=${release_branch}" >> "$GITHUB_ENV"
61
+
62
+ git config user.name "github-actions[bot]"
63
+ git config user.email "github-actions[bot]@users.noreply.github.com"
64
+ git commit -am "Bump version to ${version}"
65
+ git push origin "HEAD:${release_branch}"
66
+
67
+ - name: Open release PR
68
+ uses: peter-evans/create-pull-request@v6
69
+ with:
70
+ token: ${{ secrets.GITHUB_TOKEN }}
71
+ add-paths: |
72
+ lib/rspec/openapi/version.rb
73
+ branch: ${{ env.RELEASE_BRANCH }}
74
+ title: Release v${{ env.VERSION_NO_V }}
75
+ commit-message: Bump version to ${{ env.VERSION_NO_V }}
76
+ body: |
77
+ Automated release PR created by workflow_dispatch.
78
+ - Version: v${{ env.VERSION_NO_V }}
79
+ - Triggered by: ${{ github.actor }}
@@ -0,0 +1,46 @@
1
+ name: Publish to RubyGems
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ jobs:
9
+ publish:
10
+ name: Publish gem and GitHub release
11
+ runs-on: ubuntu-latest
12
+
13
+ permissions:
14
+ id-token: write # for RubyGems trusted publishing
15
+ contents: write # to create GitHub release
16
+
17
+ steps:
18
+ - uses: actions/checkout@v5
19
+ with:
20
+ fetch-depth: 0
21
+
22
+ - name: Set up Ruby
23
+ uses: ruby/setup-ruby@v1
24
+ with:
25
+ bundler-cache: true
26
+ ruby-version: ruby
27
+
28
+ - name: Verify tag matches version.rb
29
+ run: |
30
+ set -euo pipefail
31
+ tag="${GITHUB_REF_NAME}"
32
+ version="${tag#v}"
33
+ file_version=$(ruby -e "require_relative './lib/rspec/openapi/version'; puts RSpec::OpenAPI::VERSION")
34
+ if [ "$version" != "$file_version" ]; then
35
+ echo "Tag version ($version) does not match lib/rspec/openapi/version.rb ($file_version)" >&2
36
+ exit 1
37
+ fi
38
+
39
+ - uses: rubygems/release-gem@v1
40
+
41
+ - name: Create GitHub release
42
+ uses: softprops/action-gh-release@v2
43
+ with:
44
+ tag_name: ${{ github.ref_name }}
45
+ name: ${{ github.ref_name }}
46
+ generate_release_notes: true
@@ -14,7 +14,7 @@ jobs:
14
14
 
15
15
  steps:
16
16
  - name: Checkout repository
17
- uses: actions/checkout@v5
17
+ uses: actions/checkout@v6
18
18
 
19
19
  - name: Set up Ruby
20
20
  uses: ruby/setup-ruby@v1
@@ -32,7 +32,7 @@ jobs:
32
32
  RAILS_VERSION: ${{ matrix.rails == '' && '6.1.6' || matrix.rails }}
33
33
  COVERAGE: ${{ matrix.coverage || '' }}
34
34
  steps:
35
- - uses: actions/checkout@v5
35
+ - uses: actions/checkout@v6
36
36
  - name: bundle install
37
37
  run: bundle install -j$(nproc) --retry 3
38
38
  - run: bundle exec rspec
data/.gitignore CHANGED
@@ -7,6 +7,7 @@
7
7
  /spec/reports/
8
8
  /tmp/
9
9
  /Gemfile.lock
10
+ /vendor/
10
11
  .DS_Store
11
12
 
12
13
  # rspec failure tracking
data/README.md CHANGED
@@ -410,9 +410,10 @@ Existing RSpec plugins which have OpenAPI integration:
410
410
 
411
411
  ## Releasing
412
412
 
413
- 1. Bump version in `lib/rspec/openapi/version.rb`
414
- 2. Run `bundle exec rake release`
415
- 3. Push tag
413
+ 1. Ensure RubyGems trusted publishing is configured for this repo and gem ownership (see [Trusted publishing](https://guides.rubygems.org/trusted-publishing/)).
414
+ 2. In GitHub Actions, run the `prepare release` workflow manually. It bumps `lib/rspec/openapi/version.rb`, pushes `release/v<version>` to origin, and opens a PR.
415
+ 3. Review and merge the release PR into the default branch.
416
+ 4. Create and push a tag `v<version>` on the merged commit (via the GitHub UI or `git tag v<version>; git push origin v<version>`). Tag creation triggers the `Publish to RubyGems` workflow, which publishes the gem and creates the GitHub release notes automatically.
416
417
 
417
418
  ## License
418
419
 
@@ -256,12 +256,19 @@ class << RSpec::OpenAPI::SchemaBuilder = Object.new
256
256
  all_keys = all_schemas.flat_map { |s| s[:properties]&.keys || [] }.uniq
257
257
 
258
258
  all_keys.each do |key|
259
- property_variations = all_schemas.map { |s| s[:properties]&.[](key) }.compact
259
+ all_property_schemas = all_schemas.map { |s| s[:properties]&.[](key) }
260
260
 
261
- next if property_variations.empty?
261
+ nullable_only_schemas = all_property_schemas.select { |p| p && p.keys == [:nullable] }
262
+ property_variations = all_property_schemas.select { |p| p && p.keys != [:nullable] }
262
263
 
263
- if property_variations.size == 1
264
- merged_schema[:properties][key] = make_property_nullable(property_variations.first)
264
+ has_nullable = all_property_schemas.any?(&:nil?) || nullable_only_schemas.any?
265
+
266
+ next if property_variations.empty? && !has_nullable
267
+
268
+ if property_variations.empty? && has_nullable
269
+ merged_schema[:properties][key] = { nullable: true }
270
+ elsif property_variations.size == 1
271
+ merged_schema[:properties][key] = property_variations.first.dup
265
272
  else
266
273
  unique_types = property_variations.map { |p| p[:type] }.compact.uniq
267
274
 
@@ -275,9 +282,9 @@ class << RSpec::OpenAPI::SchemaBuilder = Object.new
275
282
  else
276
283
  merged_schema[:properties][key] = property_variations.first.dup
277
284
  end
278
-
279
- merged_schema[:properties][key][:nullable] = true if property_variations.size < all_schemas.size
280
285
  end
286
+
287
+ merged_schema[:properties][key][:nullable] = true if has_nullable && merged_schema[:properties][key].is_a?(Hash)
281
288
  end
282
289
 
283
290
  all_required_sets = all_schemas.map { |s| s[:required] || [] }
@@ -297,21 +304,34 @@ class << RSpec::OpenAPI::SchemaBuilder = Object.new
297
304
  all_keys = variations.flat_map { |v| v[:properties]&.keys || [] }.uniq
298
305
 
299
306
  all_keys.each do |key|
300
- prop_variations = variations.map { |v| v[:properties]&.[](key) }.compact
307
+ all_prop_variations = variations.map { |v| v[:properties]&.[](key) }
301
308
 
302
- if prop_variations.size == 1
303
- merged[:properties][key] = make_property_nullable(prop_variations.first)
309
+ nullable_only = all_prop_variations.select { |p| p && p.keys == [:nullable] }
310
+ prop_variations = all_prop_variations.select { |p| p && p.keys != [:nullable] }.compact
311
+
312
+ has_nullable = all_prop_variations.any?(&:nil?) || nullable_only.any?
313
+
314
+ if prop_variations.empty? && has_nullable
315
+ merged[:properties][key] = { nullable: true }
316
+ elsif prop_variations.size == 1
317
+ merged[:properties][key] = prop_variations.first.dup
318
+ merged[:properties][key][:nullable] = true if has_nullable
304
319
  elsif prop_variations.size > 1
305
320
  prop_types = prop_variations.map { |p| p[:type] }.compact.uniq
306
321
 
307
322
  if prop_types.size == 1
308
- merged[:properties][key] = prop_variations.first.dup
323
+ # Only recursively merge if it's an object type
324
+ merged[:properties][key] = if prop_types.first == 'object'
325
+ build_merged_schema_from_variations(prop_variations)
326
+ else
327
+ prop_variations.first.dup
328
+ end
309
329
  else
310
330
  unique_props = prop_variations.map { |p| p.reject { |k, _| k == :nullable } }.uniq
311
331
  merged[:properties][key] = { oneOf: unique_props }
312
332
  end
313
333
 
314
- merged[:properties][key][:nullable] = true if prop_variations.size < variations.size
334
+ merged[:properties][key][:nullable] = true if has_nullable || prop_variations.size < variations.size
315
335
  end
316
336
  end
317
337
 
@@ -323,56 +343,4 @@ class << RSpec::OpenAPI::SchemaBuilder = Object.new
323
343
  variations.first
324
344
  end
325
345
  end
326
-
327
- def merge_object_schemas(schema1, schema2)
328
- return schema1 unless schema2.is_a?(Hash) && schema1.is_a?(Hash)
329
- return schema1 unless schema1[:type] == 'object' && schema2[:type] == 'object'
330
-
331
- merged = schema1.dup
332
-
333
- if schema1[:properties] && schema2[:properties]
334
- merged[:properties] = schema1[:properties].dup
335
-
336
- schema2[:properties].each do |key, prop2|
337
- if merged[:properties][key]
338
- prop1 = merged[:properties][key]
339
- merged[:properties][key] = merge_property_schemas(prop1, prop2)
340
- else
341
- merged[:properties][key] = make_property_nullable(prop2)
342
- end
343
- end
344
-
345
- schema1[:properties].each do |key, prop1|
346
- merged[:properties][key] = make_property_nullable(prop1) unless schema2[:properties][key]
347
- end
348
-
349
- required1 = Set.new(schema1[:required] || [])
350
- required2 = Set.new(schema2[:required] || [])
351
- merged[:required] = (required1 & required2).to_a
352
- end
353
-
354
- merged
355
- end
356
-
357
- def merge_property_schemas(prop1, prop2)
358
- return prop1 unless prop2.is_a?(Hash) && prop1.is_a?(Hash)
359
-
360
- merged = prop1.dup
361
-
362
- # If either property is nullable, the merged property should be nullable
363
- merged[:nullable] = true if prop2[:nullable] && !prop1[:nullable]
364
-
365
- # If both are objects, recursively merge their properties
366
- merged = merge_object_schemas(prop1, prop2) if prop1[:type] == 'object' && prop2[:type] == 'object'
367
-
368
- merged
369
- end
370
-
371
- def make_property_nullable(property)
372
- return property unless property.is_a?(Hash)
373
-
374
- nullable_prop = property.dup
375
- nullable_prop[:nullable] = true unless nullable_prop[:nullable]
376
- nullable_prop
377
- end
378
346
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RSpec
4
4
  module OpenAPI
5
- VERSION = '0.21.1'
5
+ VERSION = '0.21.3'
6
6
  end
7
7
  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.21.1
4
+ version: 0.21.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Takashi Kokubun
@@ -63,6 +63,8 @@ files:
63
63
  - ".github/dependabot.yml"
64
64
  - ".github/release.yaml"
65
65
  - ".github/workflows/codeql-analysis.yml"
66
+ - ".github/workflows/create_release.yml"
67
+ - ".github/workflows/publish.yml"
66
68
  - ".github/workflows/rubocop.yml"
67
69
  - ".github/workflows/test.yml"
68
70
  - ".gitignore"
@@ -108,7 +110,7 @@ licenses:
108
110
  metadata:
109
111
  homepage_uri: https://github.com/exoego/rspec-openapi
110
112
  source_code_uri: https://github.com/exoego/rspec-openapi
111
- changelog_uri: https://github.com/exoego/rspec-openapi/releases/tag/v0.21.1
113
+ changelog_uri: https://github.com/exoego/rspec-openapi/releases/tag/v0.21.3
112
114
  rubygems_mfa_required: 'true'
113
115
  rdoc_options: []
114
116
  require_paths: