rspec-openapi 0.27.0 → 0.29.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: 48caaf42c5ceaca30f18251c5bf29f427e71385d188f5abcc01295de3eab55b4
4
- data.tar.gz: 171aacce0afccc800c6f5fb1e696dcd2f7d124ad0d09044e7797eb0a353452da
3
+ metadata.gz: 97857dc0658df5323bf3997e3acc31cf8f8b2f713a2d2ec6e3fdb0be7661aaf5
4
+ data.tar.gz: 9ecdb6c88c4c58042f805d899cda3d50fe2b670286de4d7f64b3799fd1ee5d48
5
5
  SHA512:
6
- metadata.gz: 9a6f77ff9446f74a56bc49576c6340176a58a6a0097e5d96a6b0a5f4334e06dfae55704a2e7dee3f1e12e160cea2a59933616ce2be8e60466f2c9ff10df460ac
7
- data.tar.gz: f75d0f697a19d72408033e8e538643334649c2a7dab832c09e96d47f53f5be2660571d7a2b8b05cc5fdcb1d43fe86e9851f9d5d8e33a4fde8375d12120aa1c2f
6
+ metadata.gz: 14577c70d8caca9754f4893be1720ed67dbb4762f1479a4454e188cc954ba8e9651f887cc0c69a95c91c1c98f994739bf12667f7470a491b60f9f2ce21ac81fc
7
+ data.tar.gz: feb18e9c32bed1f101dca61683e30975857257999fac322ff9ed51519a7ac13d583ad1cf68b3f20c56782919c9bb2d6d83d94396204c3287c468c692b1b121e1
data/README.md CHANGED
@@ -116,6 +116,10 @@ RSpec::OpenAPI.path = 'doc/schema.yaml'
116
116
  # Change the output type to JSON
117
117
  RSpec::OpenAPI.path = 'doc/schema.json'
118
118
 
119
+ # Or emit the same schema in multiple formats from a single run by passing an array.
120
+ # The output format of each file is still chosen by its extension (`.json` -> JSON, otherwise YAML).
121
+ RSpec::OpenAPI.path = ['doc/openapi.yaml', 'doc/openapi.json']
122
+
119
123
  # Or generate multiple partial schema files, given an RSpec example
120
124
  RSpec::OpenAPI.path = -> (example) {
121
125
  case example.file_path
@@ -125,6 +129,12 @@ RSpec::OpenAPI.path = -> (example) {
125
129
  end
126
130
  }
127
131
 
132
+ # The two can be combined: a proc may also return an array to fan a partial schema out to multiple formats.
133
+ RSpec::OpenAPI.path = -> (example) {
134
+ base = example.file_path.match?(%r[spec/requests/api/v2/]) ? 'doc/openapi/v2' : 'doc/openapi'
135
+ ["#{base}.yaml", "#{base}.json"]
136
+ }
137
+
128
138
  # Change the default title of the generated schema
129
139
  RSpec::OpenAPI.title = 'OpenAPI Documentation'
130
140
 
@@ -190,10 +200,16 @@ RSpec::OpenAPI.description_builder = -> (example) { example.description }
190
200
 
191
201
  # Generate a custom summary, given an RSpec example
192
202
  # This example uses the summary from the example_group.
203
+ # NOTE: a fixed `dig` only reaches one specific depth. `summary` declared on an
204
+ # ancestor group is already inherited automatically (see "Inheritance of
205
+ # `openapi:` metadata"), so a builder is only needed for fully custom logic.
193
206
  RSpec::OpenAPI.summary_builder = ->(example) { example.metadata.dig(:example_group, :openapi, :summary) }
194
207
 
195
208
  # Generate a custom tags, given an RSpec example
196
- # This example uses the tags from the parent_example_group
209
+ # This example uses the tags from the parent_example_group.
210
+ # NOTE: `dig(:example_group, :parent_example_group, ...)` only matches tags
211
+ # declared exactly two levels up; it won't find tags on deeper ancestors. Rely
212
+ # on the built-in inheritance unless you need custom resolution.
197
213
  RSpec::OpenAPI.tags_builder = -> (example) { example.metadata.dig(:example_group, :parent_example_group, :openapi, :tags) }
198
214
 
199
215
  # Configure custom format for specific properties
@@ -369,6 +385,26 @@ end
369
385
 
370
386
  **NOTE**: `description` key will override also the one provided by `RSpec::OpenAPI.description_builder` method.
371
387
 
388
+ ### Inheritance of `openapi:` metadata
389
+
390
+ `openapi:` metadata is inherited from the surrounding `describe`/`context` groups down to each
391
+ example, at any nesting depth. Inner levels override outer ones key by key, so a nested group only
392
+ needs to declare the keys it wants to change:
393
+
394
+ ```rb
395
+ describe 'GET /tables', openapi: { summary: 'Get a list of tables', tags: %w[Table] } do
396
+ context 'with pagination', openapi: { example_mode: :multiple } do
397
+ # This example inherits summary: 'Get a list of tables' and tags: ['Table']
398
+ # from the outer describe, and adds example_mode: :multiple.
399
+ it { get '/tables', params: { page: 1 } }
400
+ end
401
+ end
402
+ ```
403
+
404
+ The merge happens at the top level of the `openapi:` hash. Scalar keys (`summary`, `operation_id`,
405
+ …) follow last-wins, and a nested level that re-declares a structured key (`tags`, `security`,
406
+ `enum`, …) replaces the inherited value for that key rather than deep-merging it.
407
+
372
408
  ### Enum Support
373
409
 
374
410
  You can specify enum values for string properties that should have a fixed set of allowed values. Since enums cannot be
@@ -86,14 +86,12 @@ class SharedExtractor
86
86
 
87
87
  def self.collect_openapi_metadata(metadata)
88
88
  [].tap do |result|
89
- current = metadata
89
+ result.unshift(metadata[:openapi]) if metadata[:openapi]
90
90
 
91
- while current
92
- [current[:example_group], current].each do |meta|
93
- result.unshift(meta[:openapi]) if meta&.dig(:openapi)
94
- end
95
-
96
- current = current[:parent_example_group]
91
+ group = metadata.fetch(:example_group) { metadata[:parent_example_group] }
92
+ while group
93
+ result.unshift(group[:openapi]) if group[:openapi]
94
+ group = group[:parent_example_group]
97
95
  end
98
96
  end
99
97
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'logger'
3
4
  require 'action_dispatch'
4
5
  require 'rspec/openapi/record'
5
6
 
@@ -7,31 +7,16 @@ class RSpec::OpenAPI::ResultRecorder
7
7
  end
8
8
 
9
9
  def record_results!
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
10
+ @path_records.each do |paths, records|
11
+ # A single record set may target multiple output files (e.g. both YAML and
12
+ # JSON). The first path is the canonical source we read/merge into; the rest
13
+ # mirror the same built spec, each formatted by its own extension.
14
+ primary, *mirrors = Array(paths)
15
+ next if primary.nil?
18
16
 
19
- title = records.first.title
20
- RSpec::OpenAPI::SchemaFile.new(path).edit do |spec|
21
- schema = RSpec::OpenAPI::DefaultSchema.build(title)
22
- schema[:info].merge!(RSpec::OpenAPI.info)
23
- RSpec::OpenAPI::SchemaMerger.merge!(spec, schema)
24
- new_from_zero = {}
25
- records.each do |record|
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
31
- end
32
- cleanup_schema!(new_from_zero, spec)
33
- execute_post_process_hook(path, records, spec)
34
- end
17
+ load_path_config(primary)
18
+ built_spec = build_spec(primary, records)
19
+ mirrors.each { |mirror_path| RSpec::OpenAPI::SchemaFile.new(mirror_path).write(built_spec) }
35
20
  end
36
21
  end
37
22
 
@@ -49,6 +34,33 @@ class RSpec::OpenAPI::ResultRecorder
49
34
 
50
35
  private
51
36
 
37
+ # Look for a path-specific config file and run it.
38
+ def load_path_config(path)
39
+ config_file = File.join(File.dirname(path), RSpec::OpenAPI.config_filename)
40
+ require config_file if File.exist?(config_file)
41
+ rescue StandardError => e
42
+ puts "WARNING: Unable to load #{config_file}: #{e}"
43
+ end
44
+
45
+ def build_spec(primary, records)
46
+ title = records.first.title
47
+ RSpec::OpenAPI::SchemaFile.new(primary).edit do |spec|
48
+ schema = RSpec::OpenAPI::DefaultSchema.build(title)
49
+ schema[:info].merge!(RSpec::OpenAPI.info)
50
+ RSpec::OpenAPI::SchemaMerger.merge!(spec, schema)
51
+ new_from_zero = {}
52
+ records.each do |record|
53
+ record_schema = RSpec::OpenAPI::SchemaBuilder.build(record)
54
+ RSpec::OpenAPI::SchemaMerger.merge!(spec, record_schema)
55
+ RSpec::OpenAPI::SchemaMerger.merge!(new_from_zero, record_schema)
56
+ rescue StandardError, NotImplementedError => e # e.g. SchemaBuilder raises a NotImplementedError
57
+ @error_records[e] = record # Avoid failing the build
58
+ end
59
+ cleanup_schema!(new_from_zero, spec)
60
+ execute_post_process_hook(primary, records, spec)
61
+ end
62
+ end
63
+
52
64
  def execute_post_process_hook(path, records, spec)
53
65
  RSpec::OpenAPI.post_process_hook.call(path, records, spec) if RSpec::OpenAPI.post_process_hook.is_a?(Proc)
54
66
  end
@@ -327,16 +327,30 @@ class << RSpec::OpenAPI::SchemaBuilder
327
327
 
328
328
  def build_merged_schema_from_variations(variations)
329
329
  return {} if variations.empty?
330
- return variations.first if variations.size == 1
331
330
 
332
- types = variations.map { |v| v[:type] }.compact.uniq
333
- return variations.first unless types.size == 1 && types.first == 'object'
331
+ # Drop empty `{}` schemas (e.g. items of an empty array) — they carry no
332
+ # type info and would otherwise spuriously mark every property of their
333
+ # populated siblings as nullable via the missing-key nullable rule.
334
+ non_empty = variations.reject(&:empty?)
335
+ return {} if non_empty.empty?
336
+ return non_empty.first if non_empty.size == 1
334
337
 
335
- {
336
- type: 'object',
337
- properties: merge_property_variations(variations, allow_recursive_merge: true),
338
- required: variations.map { |v| v[:required] || [] }.reduce(:&) || [],
339
- }
338
+ types = non_empty.map { |v| v[:type] }.compact.uniq
339
+ return one_of_schema(non_empty) if types.size > 1
340
+
341
+ case types.first
342
+ when 'object'
343
+ {
344
+ type: 'object',
345
+ properties: merge_property_variations(non_empty, allow_recursive_merge: true),
346
+ required: non_empty.map { |v| v[:required] || [] }.reduce(:&) || [],
347
+ }
348
+ when 'array'
349
+ items_variations = non_empty.map { |v| v[:items] }.compact
350
+ { type: 'array', items: build_merged_schema_from_variations(items_variations) }
351
+ else
352
+ non_empty.first
353
+ end
340
354
  end
341
355
 
342
356
  # Merge the per-key property schemas of multiple object variations.
@@ -377,10 +391,8 @@ class << RSpec::OpenAPI::SchemaBuilder
377
391
  merged =
378
392
  if prop_variations.size == 1
379
393
  prop_variations.first.dup
380
- elsif allow_recursive_merge
381
- merge_multi_recursive(prop_variations)
382
394
  else
383
- merge_multi_array_items(prop_variations)
395
+ merge_multi(prop_variations)
384
396
  end
385
397
 
386
398
  return merged unless merged.is_a?(Hash)
@@ -397,13 +409,16 @@ class << RSpec::OpenAPI::SchemaBuilder
397
409
  merged
398
410
  end
399
411
 
400
- # Array-items mode: combine multiple variations of the same property without
401
- # recursing into nested objects/arrays beyond one level.
402
- def merge_multi_array_items(prop_variations)
403
- unique_types = prop_variations.map { |p| p[:type] }.compact.uniq
404
- return one_of_schema(prop_variations) if unique_types.size > 1
412
+ # Combine multiple variations of the same property: flatten existing oneOf
413
+ # entries, recurse into objects and arrays, and combine divergent types into
414
+ # oneOf. Scalar variations of a single type collapse to the first schema.
415
+ def merge_multi(prop_variations)
416
+ return { oneOf: flatten_one_of(prop_variations) } if prop_variations.any? { |p| p.key?(:oneOf) }
405
417
 
406
- case unique_types.first
418
+ prop_types = prop_variations.map { |p| p[:type] }.compact.uniq
419
+ return one_of_schema(prop_variations) if prop_types.size > 1
420
+
421
+ case prop_types.first
407
422
  when 'array'
408
423
  items_variations = prop_variations.map { |p| p[:items] }.compact
409
424
  { type: 'array', items: build_merged_schema_from_variations(items_variations) }
@@ -414,17 +429,6 @@ class << RSpec::OpenAPI::SchemaBuilder
414
429
  end
415
430
  end
416
431
 
417
- # Recursive-merge mode (used inside build_merged_schema_from_variations):
418
- # additionally flattens existing oneOf entries and recurses into objects.
419
- def merge_multi_recursive(prop_variations)
420
- return { oneOf: flatten_one_of(prop_variations) } if prop_variations.any? { |p| p.key?(:oneOf) }
421
-
422
- prop_types = prop_variations.map { |p| p[:type] }.compact.uniq
423
- return one_of_schema(prop_variations) if prop_types.size > 1
424
-
425
- prop_types.first == 'object' ? build_merged_schema_from_variations(prop_variations) : prop_variations.first.dup
426
- end
427
-
428
432
  def flatten_one_of(prop_variations)
429
433
  prop_variations.each_with_object([]) do |prop, options|
430
434
  clean = without_nullable(prop)
@@ -14,11 +14,30 @@ class RSpec::OpenAPI::SchemaFile
14
14
  @path = path
15
15
  end
16
16
 
17
+ # Reads the existing spec, lets the block mutate it, writes the result back
18
+ # and returns the (symbolized) spec so it can be mirrored to other files.
19
+ # @return [Hash]
17
20
  def edit(&block)
18
21
  spec = read
19
22
  block.call(spec)
23
+ spec
20
24
  ensure
21
- write(RSpec::OpenAPI::KeyTransformer.stringify(spec))
25
+ write(spec)
26
+ end
27
+
28
+ # Writes an already-built spec to this file, choosing the format from the
29
+ # file extension.
30
+ # @param [Hash] spec
31
+ def write(spec)
32
+ stringified = RSpec::OpenAPI::KeyTransformer.stringify(spec)
33
+ FileUtils.mkdir_p(File.dirname(@path))
34
+ output =
35
+ if json?
36
+ JSON.pretty_generate(stringified)
37
+ else
38
+ prepend_comment(YAML.dump(stringified))
39
+ end
40
+ File.write(@path, output)
22
41
  end
23
42
 
24
43
  private
@@ -33,18 +52,6 @@ class RSpec::OpenAPI::SchemaFile
33
52
  RSpec::OpenAPI::KeyTransformer.symbolize(content)
34
53
  end
35
54
 
36
- # @param [Hash] spec
37
- def write(spec)
38
- FileUtils.mkdir_p(File.dirname(@path))
39
- output =
40
- if json?
41
- JSON.pretty_generate(spec)
42
- else
43
- prepend_comment(YAML.dump(spec))
44
- end
45
- File.write(@path, output)
46
- end
47
-
48
55
  def prepend_comment(content)
49
56
  return content if RSpec::OpenAPI.comment.nil?
50
57
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RSpec
4
4
  module OpenAPI
5
- VERSION = '0.27.0'
5
+ VERSION = '0.29.0'
6
6
  end
7
7
  end
@@ -22,10 +22,10 @@ Gem::Specification.new do |spec|
22
22
  }
23
23
 
24
24
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
25
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ `git ls-files -z`.split("\x0").select do |f|
26
+ f.start_with?('lib/') || ['LICENSE.txt', 'README.md', 'rspec-openapi.gemspec'].include?(f)
27
+ end
26
28
  end
27
- spec.bindir = 'exe'
28
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
29
  spec.require_paths = ['lib']
30
30
 
31
31
  spec.add_dependency 'actionpack', '>= 5.2.0'
metadata CHANGED
@@ -1,12 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-openapi
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.27.0
4
+ version: 0.29.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Takashi Kokubun
8
8
  - TATSUNO Yasuhiro
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
11
  date: 1980-01-02 00:00:00.000000000 Z
12
12
  dependencies:
@@ -60,26 +60,8 @@ executables: []
60
60
  extensions: []
61
61
  extra_rdoc_files: []
62
62
  files:
63
- - ".github/dependabot.yml"
64
- - ".github/release.yaml"
65
- - ".github/workflows/codeql-analysis.yml"
66
- - ".github/workflows/create_release.yml"
67
- - ".github/workflows/publish.yml"
68
- - ".github/workflows/rubocop.yml"
69
- - ".github/workflows/test.yml"
70
- - ".github/workflows/validate-openapi.yml"
71
- - ".gitignore"
72
- - ".rspec"
73
- - ".rubocop.yml"
74
- - ".rubocop_todo.yml"
75
- - ".simplecov_spawn.rb"
76
- - CHANGELOG.md
77
- - Gemfile
78
63
  - LICENSE.txt
79
64
  - README.md
80
- - Rakefile
81
- - bin/console
82
- - bin/setup
83
65
  - lib/rspec/openapi.rb
84
66
  - lib/rspec/openapi/components_updater.rb
85
67
  - lib/rspec/openapi/default_schema.rb
@@ -104,18 +86,14 @@ files:
104
86
  - lib/rspec/openapi/schema_sorter.rb
105
87
  - lib/rspec/openapi/shared_hooks.rb
106
88
  - lib/rspec/openapi/version.rb
107
- - redocly.yaml
108
89
  - rspec-openapi.gemspec
109
- - scripts/rspec
110
- - scripts/rspec_with_simplecov
111
- - test.png
112
90
  homepage: https://github.com/exoego/rspec-openapi
113
91
  licenses:
114
92
  - MIT
115
93
  metadata:
116
94
  homepage_uri: https://github.com/exoego/rspec-openapi
117
95
  source_code_uri: https://github.com/exoego/rspec-openapi
118
- changelog_uri: https://github.com/exoego/rspec-openapi/releases/tag/v0.27.0
96
+ changelog_uri: https://github.com/exoego/rspec-openapi/releases/tag/v0.29.0
119
97
  rubygems_mfa_required: 'true'
120
98
  rdoc_options: []
121
99
  require_paths:
@@ -1,8 +0,0 @@
1
- version: 2
2
- updates:
3
- - package-ecosystem: "github-actions"
4
- directory: "/"
5
- schedule:
6
- interval: "monthly"
7
- labels:
8
- - "chore"
data/.github/release.yaml DELETED
@@ -1,24 +0,0 @@
1
- changelog:
2
- exclude:
3
- labels:
4
- - ignore-for-release
5
- authors:
6
- - octocat
7
- categories:
8
- - title: 🛠 Breaking Changes
9
- labels:
10
- - semver-major
11
- - breaking-change
12
- - title: 🎉 Exciting New Features
13
- labels:
14
- - semver-minor
15
- - enhancement
16
- - title: 🐞 Bugfixes
17
- labels:
18
- - bug
19
- - title: 📄 Documentation
20
- labels:
21
- - documentation
22
- - title: 📦 Other Changes
23
- labels:
24
- - "*"
@@ -1,39 +0,0 @@
1
- name: "CodeQL"
2
-
3
- on:
4
- push:
5
- branches: [ "master" ]
6
- pull_request:
7
- # The branches below must be a subset of the branches above
8
- branches: [ "master" ]
9
- schedule:
10
- - cron: '20 22 * * 2'
11
-
12
- jobs:
13
- analyze:
14
- name: Analyze
15
- runs-on: ubuntu-latest
16
- permissions:
17
- actions: read
18
- contents: read
19
- security-events: write
20
-
21
- strategy:
22
- fail-fast: false
23
- matrix:
24
- language: [ 'ruby' ]
25
-
26
- steps:
27
- - name: Checkout repository
28
- uses: actions/checkout@v6
29
-
30
- - name: Initialize CodeQL
31
- uses: github/codeql-action/init@v4
32
- with:
33
- languages: ${{ matrix.language }}
34
-
35
- - name: Autobuild
36
- uses: github/codeql-action/autobuild@v4
37
-
38
- - name: Perform CodeQL Analysis
39
- uses: github/codeql-action/analyze@v4
@@ -1,95 +0,0 @@
1
- name: prepare release
2
-
3
- on:
4
- workflow_dispatch:
5
- inputs:
6
- version:
7
- description: 'Version to release (e.g. 0.27.1 or 0.28.0)'
8
- required: true
9
-
10
- jobs:
11
- push:
12
- name: Prepare release PR
13
- runs-on: ubuntu-latest
14
-
15
- steps:
16
- - uses: actions/checkout@v6
17
- with:
18
- fetch-depth: 0
19
- token: ${{ secrets.PREPARE_RELEASE_PAT }}
20
-
21
- - name: Bump version.rb
22
- run: |
23
- set -euo pipefail
24
- version="${{ github.event.inputs.version }}"
25
- version="${version#v}"
26
-
27
- echo "VERSION_NO_V=$version" >> "$GITHUB_ENV"
28
- echo "VERSION_TAG=v$version" >> "$GITHUB_ENV"
29
-
30
- current_version=$(ruby -e "require_relative './lib/rspec/openapi/version'; puts RSpec::OpenAPI::VERSION")
31
- VERSION_NO_V="$version" CURRENT_VERSION="$current_version" ruby - <<'RUBY'
32
- version = ENV.fetch('VERSION_NO_V')
33
- unless version.match?(/\A\d+(?:\.\d+)*\z/)
34
- warn "Invalid version format: #{version}"
35
- exit 1
36
- end
37
-
38
- require 'rubygems'
39
- new_version = Gem::Version.new(version)
40
- current_version = Gem::Version.new(ENV.fetch('CURRENT_VERSION'))
41
- if new_version <= current_version
42
- warn "Given version (#{new_version}) must be newer than current version (#{current_version})"
43
- exit 1
44
- end
45
- RUBY
46
- ruby -pi -e "sub(/VERSION = .*/, \"VERSION = '$version'\")" lib/rspec/openapi/version.rb
47
-
48
- VERSION_NO_V="$version" ruby - <<'RUBY'
49
- version = ENV.fetch('VERSION_NO_V')
50
- segments = version.split('.').map(&:to_i)
51
- unless segments.size >= 3
52
- warn "Version must have at least major.minor.patch: #{version}"
53
- exit 1
54
- end
55
-
56
- major, minor, patch = segments
57
- patch_bump = [major, minor, patch + 1].join('.')
58
- minor_bump = [major, minor + 1, 0].join('.')
59
- example = "Version to release (e.g. #{patch_bump} or #{minor_bump})"
60
-
61
- path = ".github/workflows/create_release.yml"
62
- content = File.read(path)
63
- content.sub!(/description:\s*'Version to release \(e\.g\. [^']+\)'/,
64
- "description: '#{example}'")
65
- File.write(path, content)
66
- RUBY
67
- git status --short
68
-
69
- - name: Commit version bump
70
- run: |
71
- set -euo pipefail
72
- version="$VERSION_NO_V"
73
-
74
- release_branch="release/v${version}"
75
- echo "RELEASE_BRANCH=${release_branch}" >> "$GITHUB_ENV"
76
-
77
- git config user.name "github-actions[bot]"
78
- git config user.email "github-actions[bot]@users.noreply.github.com"
79
- git commit -am "Bump version to ${version}"
80
- git push origin "HEAD:${release_branch}"
81
-
82
- - name: Open release PR
83
- uses: peter-evans/create-pull-request@v8
84
- with:
85
- token: ${{ secrets.PREPARE_RELEASE_PAT }}
86
- add-paths: |
87
- lib/rspec/openapi/version.rb
88
- .github/workflows/create_release.yml
89
- branch: ${{ env.RELEASE_BRANCH }}
90
- title: Release v${{ env.VERSION_NO_V }}
91
- commit-message: Bump version to ${{ env.VERSION_NO_V }}
92
- body: |
93
- Automated release PR created by workflow_dispatch.
94
- - Version: v${{ env.VERSION_NO_V }}
95
- - Triggered by: ${{ github.actor }}
@@ -1,46 +0,0 @@
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@v6
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: '4.0'
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@v3
43
- with:
44
- tag_name: ${{ github.ref_name }}
45
- name: ${{ github.ref_name }}
46
- generate_release_notes: true
@@ -1,35 +0,0 @@
1
- name: "Rubocop"
2
-
3
- on:
4
- push:
5
- branches: [ "master" ]
6
- pull_request:
7
- branches: [ "master" ]
8
-
9
- jobs:
10
- rubocop:
11
- runs-on: ubuntu-latest
12
- strategy:
13
- fail-fast: false
14
-
15
- steps:
16
- - name: Checkout repository
17
- uses: actions/checkout@v6
18
-
19
- - name: Set up Ruby
20
- uses: ruby/setup-ruby@v1
21
- with:
22
- ruby-version: '4.0'
23
- bundler-cache: true
24
-
25
- - name: Rubocop run
26
- run: |
27
- bash -c "
28
- bundle exec rubocop --require code_scanning --format CodeScanning::SarifFormatter -o rubocop.sarif
29
- [[ $? -ne 2 ]]
30
- "
31
-
32
- - name: Upload Sarif output
33
- uses: github/codeql-action/upload-sarif@v4
34
- with:
35
- sarif_file: rubocop.sarif