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 +4 -4
- data/.github/workflows/codeql-analysis.yml +1 -1
- data/.github/workflows/create_release.yml +79 -0
- data/.github/workflows/publish.yml +46 -0
- data/.github/workflows/rubocop.yml +1 -1
- data/.github/workflows/test.yml +1 -1
- data/.gitignore +1 -0
- data/README.md +4 -3
- data/lib/rspec/openapi/schema_builder.rb +31 -63
- data/lib/rspec/openapi/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d28b278fc0d9e8f0ce356103ea53e7b97392eac4f7c09fda493a9d7b1e2bfa10
|
|
4
|
+
data.tar.gz: 501c53f68a84d09f96f40a0e0749d65b2ceba13d16ebeb4819c989fdd7f62c2e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7e4636d3f30bb1114932aabdb6ae2ef40bb9492a08d5d7c9022f52d8b5e4a415e424abc8611a14a8f7f6d8c139947ee900bc50cdfafda19e95bcd6cb06d26142
|
|
7
|
+
data.tar.gz: 8a3e455ed8a022f5e9df443a14f3159665b77ca4a416b6b3f29404efd367717060f7121fd1a3ec77190d1bc426850b58faf2cc6092c7acc9c18e8f78e732aeb7
|
|
@@ -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
|
data/.github/workflows/test.yml
CHANGED
|
@@ -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@
|
|
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
data/README.md
CHANGED
|
@@ -410,9 +410,10 @@ Existing RSpec plugins which have OpenAPI integration:
|
|
|
410
410
|
|
|
411
411
|
## Releasing
|
|
412
412
|
|
|
413
|
-
1.
|
|
414
|
-
2.
|
|
415
|
-
3.
|
|
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
|
-
|
|
259
|
+
all_property_schemas = all_schemas.map { |s| s[:properties]&.[](key) }
|
|
260
260
|
|
|
261
|
-
|
|
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
|
-
|
|
264
|
-
|
|
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
|
-
|
|
307
|
+
all_prop_variations = variations.map { |v| v[:properties]&.[](key) }
|
|
301
308
|
|
|
302
|
-
|
|
303
|
-
|
|
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
|
-
|
|
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
|
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.
|
|
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.
|
|
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:
|