Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
16 changes: 9 additions & 7 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ jobs:
deploy:
name: Deploy SDK to Rubygems
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
env:
BW_ACCOUNT_ID: ${{ secrets.BW_ACCOUNT_ID }}
BW_USERNAME: ${{ secrets.BW_USERNAME }}
Expand All @@ -22,7 +25,7 @@ jobs:
BW_NUMBER: ${{ secrets.BW_NUMBER }}
USER_NUMBER: ${{ secrets.USER_NUMBER }}
BASE_CALLBACK_URL: ${{ secrets.BASE_CALLBACK_URL }}
RUBY_VERSION: "3.0"
RUBY_VERSION: "4.0"
OPERATING_SYSTEM: "ubuntu"
MANTECA_ACTIVE_NUMBER: ${{ secrets.MANTECA_ACTIVE_NUMBER }}
MANTECA_IDLE_NUMBER: ${{ secrets.MANTECA_IDLE_NUMBER }}
Expand All @@ -47,12 +50,12 @@ jobs:
TAG: ${{ github.event.release.tag_name }}

- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v7

- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.3
ruby-version: 4.0

- name: Update Gem Version
run: sed -i "s/VERSION = '.*'/VERSION = '$GEM_VERSION'/g" lib/bandwidth-sdk/version.rb
Expand All @@ -64,12 +67,11 @@ jobs:
prism mock ./bandwidth.yml & (sleep 3; rake unit)
shell: bash

- name: Configure Rubygems Trusted Publishing Credentials
uses: rubygems/configure-rubygems-credentials@v2.1.0

- name: Deploy to Rubygems
run: |
mkdir ~/.gem
touch ~/.gem/credentials
chmod 0600 ~/.gem/credentials
printf -- "---\n:rubygems_api_key: ${{ secrets.RUBYGEMS_API_KEY }}\n" > ~/.gem/credentials
gem build *.gemspec
gem push *.gem

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/test-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-2022, windows-2025, ubuntu-22.04, ubuntu-24.04]
ruby-version: ['3.0','3.1','3.2','3.3']
os: [windows-2022, windows-2025, ubuntu-22.04, ubuntu-24.04]
ruby-version: ["3.2", "3.3", "3.4", "4.0"]
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v7

- name: Set up Ruby
uses: ruby/setup-ruby@v1
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/test-smoke.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,19 @@ jobs:
MANTECA_APPLICATION_ID: ${{ secrets.MANTECA_APPLICATION_ID }}
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@v7

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.3
ruby-version: 3.4

- name: Install Packages and Test
run: |
bundle install
rake smoke
env:
RUBY_VERSION: 3.3
RUBY_VERSION: 3.4
OPERATING_SYSTEM: ubuntu
shell: bash

Expand All @@ -66,19 +66,19 @@ jobs:
MANTECA_APPLICATION_ID: ${{ secrets.MANTECA_UP_APPLICATION_ID }}
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v7

- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.3
ruby-version: 3.4

- name: Install Packages and Test
run: |
bundle install
rake smoke
env:
RUBY_VERSION: 3.3
RUBY_VERSION: 3.4
OPERATING_SYSTEM: ubuntu
shell: bash

Expand Down
2 changes: 1 addition & 1 deletion .openapi-generator/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
7.17.0
7.24.0
19 changes: 17 additions & 2 deletions UPDATING_MODEL_TESTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ describe Bandwidth::ModelName do

describe '#to_s' do
# Use the *populated* values instance, not the empty default.
# Compare against a hash literal + .to_s, never a hardcoded string.
it 'returns a string representation of the object'
end

Expand Down Expand Up @@ -293,9 +294,23 @@ Bandwidth::VerificationRequest.build_from_hash({

Apply this recursively — if the nested model itself has nested models with required attrs, fill those too. Check the nested model's setters (`def <attr>=` blocks raising `'<attr> cannot be nil'`) to know which attrs are required.

### `#to_s` is sensitive to attribute order
### `#to_s` must not assert against a hardcoded string

The expected string must match the exact order of attributes as serialized by `to_hash`. Generate the expected string by running the populated instance through `to_s` in a console and pasting the result. Don't hand-craft it.
`ApiModelBase#to_s` is `to_hash.to_s`, so its output is whatever `Hash#inspect` produces on the running Ruby — and **that format is version-dependent**. Ruby 3.4 changed it from `{:key=>"value"}` to `{key: "value"}`, which broke every spec that pasted a literal string.

Compare against a **hash literal put through `.to_s`** instead. Ruby renders both sides with the same format, so the assertion holds on every supported version:

```ruby
# Wrong — passes on <= 3.3, fails on >= 3.4:
expect(model_values.to_s).to eq('{:type=>"validation", :id=>"abc"}')

# Right — version-agnostic:
expect(model_values.to_s).to eq({:type=>"validation", :id=>"abc"}.to_s)
```

The auto-generated spec emits the hardcoded-string form, so this needs fixing on every regeneration. The fix is mechanical: strip the surrounding quotes and append `.to_s` — the text inside the quotes is already valid Ruby hash-literal source.

**Attribute order still matters.** String comparison is order-sensitive (unlike the `Hash#==` in the `#to_body #to_hash` block), so the literal's key order must match `to_hash`'s serialization order. Keys are the *JSON* names from `attribute_map` (camelCase), not the snake_case attr names. Get the order by running the populated instance through `to_s` in a console — just convert the result to a hash literal rather than pasting it as a string.

### Nullable attribute symbols

Expand Down
4 changes: 2 additions & 2 deletions bandwidth-sdk.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
The version of the OpenAPI document: 1.0.0
Contact: letstalk@bandwidth.com
Generated by: https://openapi-generator.tech
Generator version: 7.17.0
Generator version: 7.24.0
=end

$:.push File.expand_path('../lib', __FILE__)
Expand All @@ -29,7 +29,7 @@ Gem::Specification.new do |s|

s.add_runtime_dependency 'faraday', '>= 1.0.1', '< 3.0'
s.add_runtime_dependency 'faraday-multipart'
s.add_runtime_dependency 'ox', '~> 2.14'
s.add_runtime_dependency 'ox', '~> 2.14', '>= 2.14.28'
s.add_runtime_dependency 'marcel'

s.add_development_dependency 'rspec', '~> 3.6', '>= 3.6.0'
Expand Down
2 changes: 1 addition & 1 deletion custom_templates/gemspec.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ Gem::Specification.new do |s|
{{^isFaraday}}
s.add_runtime_dependency 'typhoeus', '~> 1.0', '>= 1.0.1'
{{/isFaraday}}
s.add_runtime_dependency 'ox', '~> 2.14'
s.add_runtime_dependency 'ox', '~> 2.14', '>= 2.14.28'
s.add_runtime_dependency 'marcel'

s.add_development_dependency 'rspec', '~> 3.6', '>= 3.6.0'
Expand Down
2 changes: 1 addition & 1 deletion lib/bandwidth-sdk.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
The version of the OpenAPI document: 1.0.0
Contact: letstalk@bandwidth.com
Generated by: https://openapi-generator.tech
Generator version: 7.17.0
Generator version: 7.24.0

=end

Expand Down
12 changes: 6 additions & 6 deletions lib/bandwidth-sdk/api/calls_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
The version of the OpenAPI document: 1.0.0
Contact: letstalk@bandwidth.com
Generated by: https://openapi-generator.tech
Generator version: 7.17.0
Generator version: 7.24.0

=end

Expand Down Expand Up @@ -49,7 +49,7 @@ def create_call_with_http_info(account_id, create_call, opts = {})
fail ArgumentError, "Missing the required parameter 'create_call' when calling CallsApi.create_call"
end
# resource path
local_var_path = '/accounts/{accountId}/calls'.sub('{' + 'accountId' + '}', CGI.escape(account_id.to_s))
local_var_path = '/accounts/{accountId}/calls'.sub('{accountId}', CGI.escape(account_id.to_s))

# query parameters
query_params = opts[:query_params] || {}
Expand Down Expand Up @@ -123,7 +123,7 @@ def get_call_state_with_http_info(account_id, call_id, opts = {})
fail ArgumentError, "Missing the required parameter 'call_id' when calling CallsApi.get_call_state"
end
# resource path
local_var_path = '/accounts/{accountId}/calls/{callId}'.sub('{' + 'accountId' + '}', CGI.escape(account_id.to_s)).sub('{' + 'callId' + '}', CGI.escape(call_id.to_s))
local_var_path = '/accounts/{accountId}/calls/{callId}'.sub('{accountId}', CGI.escape(account_id.to_s)).sub('{callId}', CGI.escape(call_id.to_s))

# query parameters
query_params = opts[:query_params] || {}
Expand Down Expand Up @@ -208,7 +208,7 @@ def list_calls_with_http_info(account_id, opts = {})
end

# resource path
local_var_path = '/accounts/{accountId}/calls'.sub('{' + 'accountId' + '}', CGI.escape(account_id.to_s))
local_var_path = '/accounts/{accountId}/calls'.sub('{accountId}', CGI.escape(account_id.to_s))

# query parameters
query_params = opts[:query_params] || {}
Expand Down Expand Up @@ -290,7 +290,7 @@ def update_call_with_http_info(account_id, call_id, update_call, opts = {})
fail ArgumentError, "Missing the required parameter 'update_call' when calling CallsApi.update_call"
end
# resource path
local_var_path = '/accounts/{accountId}/calls/{callId}'.sub('{' + 'accountId' + '}', CGI.escape(account_id.to_s)).sub('{' + 'callId' + '}', CGI.escape(call_id.to_s))
local_var_path = '/accounts/{accountId}/calls/{callId}'.sub('{accountId}', CGI.escape(account_id.to_s)).sub('{callId}', CGI.escape(call_id.to_s))

# query parameters
query_params = opts[:query_params] || {}
Expand Down Expand Up @@ -370,7 +370,7 @@ def update_call_bxml_with_http_info(account_id, call_id, body, opts = {})
fail ArgumentError, "Missing the required parameter 'body' when calling CallsApi.update_call_bxml"
end
# resource path
local_var_path = '/accounts/{accountId}/calls/{callId}/bxml'.sub('{' + 'accountId' + '}', CGI.escape(account_id.to_s)).sub('{' + 'callId' + '}', CGI.escape(call_id.to_s))
local_var_path = '/accounts/{accountId}/calls/{callId}/bxml'.sub('{accountId}', CGI.escape(account_id.to_s)).sub('{callId}', CGI.escape(call_id.to_s))

# query parameters
query_params = opts[:query_params] || {}
Expand Down
20 changes: 10 additions & 10 deletions lib/bandwidth-sdk/api/conferences_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
The version of the OpenAPI document: 1.0.0
Contact: letstalk@bandwidth.com
Generated by: https://openapi-generator.tech
Generator version: 7.17.0
Generator version: 7.24.0

=end

Expand Down Expand Up @@ -55,7 +55,7 @@ def download_conference_recording_with_http_info(account_id, conference_id, reco
fail ArgumentError, "Missing the required parameter 'recording_id' when calling ConferencesApi.download_conference_recording"
end
# resource path
local_var_path = '/accounts/{accountId}/conferences/{conferenceId}/recordings/{recordingId}/media'.sub('{' + 'accountId' + '}', CGI.escape(account_id.to_s)).sub('{' + 'conferenceId' + '}', CGI.escape(conference_id.to_s)).sub('{' + 'recordingId' + '}', CGI.escape(recording_id.to_s))
local_var_path = '/accounts/{accountId}/conferences/{conferenceId}/recordings/{recordingId}/media'.sub('{accountId}', CGI.escape(account_id.to_s)).sub('{conferenceId}', CGI.escape(conference_id.to_s)).sub('{recordingId}', CGI.escape(recording_id.to_s))

# query parameters
query_params = opts[:query_params] || {}
Expand Down Expand Up @@ -124,7 +124,7 @@ def get_conference_with_http_info(account_id, conference_id, opts = {})
fail ArgumentError, "Missing the required parameter 'conference_id' when calling ConferencesApi.get_conference"
end
# resource path
local_var_path = '/accounts/{accountId}/conferences/{conferenceId}'.sub('{' + 'accountId' + '}', CGI.escape(account_id.to_s)).sub('{' + 'conferenceId' + '}', CGI.escape(conference_id.to_s))
local_var_path = '/accounts/{accountId}/conferences/{conferenceId}'.sub('{accountId}', CGI.escape(account_id.to_s)).sub('{conferenceId}', CGI.escape(conference_id.to_s))

# query parameters
query_params = opts[:query_params] || {}
Expand Down Expand Up @@ -199,7 +199,7 @@ def get_conference_member_with_http_info(account_id, conference_id, member_id, o
fail ArgumentError, "Missing the required parameter 'member_id' when calling ConferencesApi.get_conference_member"
end
# resource path
local_var_path = '/accounts/{accountId}/conferences/{conferenceId}/members/{memberId}'.sub('{' + 'accountId' + '}', CGI.escape(account_id.to_s)).sub('{' + 'conferenceId' + '}', CGI.escape(conference_id.to_s)).sub('{' + 'memberId' + '}', CGI.escape(member_id.to_s))
local_var_path = '/accounts/{accountId}/conferences/{conferenceId}/members/{memberId}'.sub('{accountId}', CGI.escape(account_id.to_s)).sub('{conferenceId}', CGI.escape(conference_id.to_s)).sub('{memberId}', CGI.escape(member_id.to_s))

# query parameters
query_params = opts[:query_params] || {}
Expand Down Expand Up @@ -274,7 +274,7 @@ def get_conference_recording_with_http_info(account_id, conference_id, recording
fail ArgumentError, "Missing the required parameter 'recording_id' when calling ConferencesApi.get_conference_recording"
end
# resource path
local_var_path = '/accounts/{accountId}/conferences/{conferenceId}/recordings/{recordingId}'.sub('{' + 'accountId' + '}', CGI.escape(account_id.to_s)).sub('{' + 'conferenceId' + '}', CGI.escape(conference_id.to_s)).sub('{' + 'recordingId' + '}', CGI.escape(recording_id.to_s))
local_var_path = '/accounts/{accountId}/conferences/{conferenceId}/recordings/{recordingId}'.sub('{accountId}', CGI.escape(account_id.to_s)).sub('{conferenceId}', CGI.escape(conference_id.to_s)).sub('{recordingId}', CGI.escape(recording_id.to_s))

# query parameters
query_params = opts[:query_params] || {}
Expand Down Expand Up @@ -343,7 +343,7 @@ def list_conference_recordings_with_http_info(account_id, conference_id, opts =
fail ArgumentError, "Missing the required parameter 'conference_id' when calling ConferencesApi.list_conference_recordings"
end
# resource path
local_var_path = '/accounts/{accountId}/conferences/{conferenceId}/recordings'.sub('{' + 'accountId' + '}', CGI.escape(account_id.to_s)).sub('{' + 'conferenceId' + '}', CGI.escape(conference_id.to_s))
local_var_path = '/accounts/{accountId}/conferences/{conferenceId}/recordings'.sub('{accountId}', CGI.escape(account_id.to_s)).sub('{conferenceId}', CGI.escape(conference_id.to_s))

# query parameters
query_params = opts[:query_params] || {}
Expand Down Expand Up @@ -424,7 +424,7 @@ def list_conferences_with_http_info(account_id, opts = {})
end

# resource path
local_var_path = '/accounts/{accountId}/conferences'.sub('{' + 'accountId' + '}', CGI.escape(account_id.to_s))
local_var_path = '/accounts/{accountId}/conferences'.sub('{accountId}', CGI.escape(account_id.to_s))

# query parameters
query_params = opts[:query_params] || {}
Expand Down Expand Up @@ -504,7 +504,7 @@ def update_conference_with_http_info(account_id, conference_id, update_conferenc
fail ArgumentError, "Missing the required parameter 'update_conference' when calling ConferencesApi.update_conference"
end
# resource path
local_var_path = '/accounts/{accountId}/conferences/{conferenceId}'.sub('{' + 'accountId' + '}', CGI.escape(account_id.to_s)).sub('{' + 'conferenceId' + '}', CGI.escape(conference_id.to_s))
local_var_path = '/accounts/{accountId}/conferences/{conferenceId}'.sub('{accountId}', CGI.escape(account_id.to_s)).sub('{conferenceId}', CGI.escape(conference_id.to_s))

# query parameters
query_params = opts[:query_params] || {}
Expand Down Expand Up @@ -584,7 +584,7 @@ def update_conference_bxml_with_http_info(account_id, conference_id, body, opts
fail ArgumentError, "Missing the required parameter 'body' when calling ConferencesApi.update_conference_bxml"
end
# resource path
local_var_path = '/accounts/{accountId}/conferences/{conferenceId}/bxml'.sub('{' + 'accountId' + '}', CGI.escape(account_id.to_s)).sub('{' + 'conferenceId' + '}', CGI.escape(conference_id.to_s))
local_var_path = '/accounts/{accountId}/conferences/{conferenceId}/bxml'.sub('{accountId}', CGI.escape(account_id.to_s)).sub('{conferenceId}', CGI.escape(conference_id.to_s))

# query parameters
query_params = opts[:query_params] || {}
Expand Down Expand Up @@ -670,7 +670,7 @@ def update_conference_member_with_http_info(account_id, conference_id, member_id
fail ArgumentError, "Missing the required parameter 'update_conference_member' when calling ConferencesApi.update_conference_member"
end
# resource path
local_var_path = '/accounts/{accountId}/conferences/{conferenceId}/members/{memberId}'.sub('{' + 'accountId' + '}', CGI.escape(account_id.to_s)).sub('{' + 'conferenceId' + '}', CGI.escape(conference_id.to_s)).sub('{' + 'memberId' + '}', CGI.escape(member_id.to_s))
local_var_path = '/accounts/{accountId}/conferences/{conferenceId}/members/{memberId}'.sub('{accountId}', CGI.escape(account_id.to_s)).sub('{conferenceId}', CGI.escape(conference_id.to_s)).sub('{memberId}', CGI.escape(member_id.to_s))

# query parameters
query_params = opts[:query_params] || {}
Expand Down
12 changes: 6 additions & 6 deletions lib/bandwidth-sdk/api/endpoints_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
The version of the OpenAPI document: 1.0.0
Contact: letstalk@bandwidth.com
Generated by: https://openapi-generator.tech
Generator version: 7.17.0
Generator version: 7.24.0

=end

Expand Down Expand Up @@ -49,7 +49,7 @@ def create_endpoint_with_http_info(account_id, body, opts = {})
fail ArgumentError, "Missing the required parameter 'body' when calling EndpointsApi.create_endpoint"
end
# resource path
local_var_path = '/accounts/{accountId}/endpoints'.sub('{' + 'accountId' + '}', CGI.escape(account_id.to_s))
local_var_path = '/accounts/{accountId}/endpoints'.sub('{accountId}', CGI.escape(account_id.to_s))

# query parameters
query_params = opts[:query_params] || {}
Expand Down Expand Up @@ -123,7 +123,7 @@ def delete_endpoint_with_http_info(account_id, endpoint_id, opts = {})
fail ArgumentError, "Missing the required parameter 'endpoint_id' when calling EndpointsApi.delete_endpoint"
end
# resource path
local_var_path = '/accounts/{accountId}/endpoints/{endpointId}'.sub('{' + 'accountId' + '}', CGI.escape(account_id.to_s)).sub('{' + 'endpointId' + '}', CGI.escape(endpoint_id.to_s))
local_var_path = '/accounts/{accountId}/endpoints/{endpointId}'.sub('{accountId}', CGI.escape(account_id.to_s)).sub('{endpointId}', CGI.escape(endpoint_id.to_s))

# query parameters
query_params = opts[:query_params] || {}
Expand Down Expand Up @@ -192,7 +192,7 @@ def get_endpoint_with_http_info(account_id, endpoint_id, opts = {})
fail ArgumentError, "Missing the required parameter 'endpoint_id' when calling EndpointsApi.get_endpoint"
end
# resource path
local_var_path = '/accounts/{accountId}/endpoints/{endpointId}'.sub('{' + 'accountId' + '}', CGI.escape(account_id.to_s)).sub('{' + 'endpointId' + '}', CGI.escape(endpoint_id.to_s))
local_var_path = '/accounts/{accountId}/endpoints/{endpointId}'.sub('{accountId}', CGI.escape(account_id.to_s)).sub('{endpointId}', CGI.escape(endpoint_id.to_s))

# query parameters
query_params = opts[:query_params] || {}
Expand Down Expand Up @@ -271,7 +271,7 @@ def list_endpoints_with_http_info(account_id, opts = {})
end

# resource path
local_var_path = '/accounts/{accountId}/endpoints'.sub('{' + 'accountId' + '}', CGI.escape(account_id.to_s))
local_var_path = '/accounts/{accountId}/endpoints'.sub('{accountId}', CGI.escape(account_id.to_s))

# query parameters
query_params = opts[:query_params] || {}
Expand Down Expand Up @@ -350,7 +350,7 @@ def update_endpoint_bxml_with_http_info(account_id, endpoint_id, body, opts = {}
fail ArgumentError, "Missing the required parameter 'body' when calling EndpointsApi.update_endpoint_bxml"
end
# resource path
local_var_path = '/accounts/{accountId}/endpoints/{endpointId}/bxml'.sub('{' + 'accountId' + '}', CGI.escape(account_id.to_s)).sub('{' + 'endpointId' + '}', CGI.escape(endpoint_id.to_s))
local_var_path = '/accounts/{accountId}/endpoints/{endpointId}/bxml'.sub('{accountId}', CGI.escape(account_id.to_s)).sub('{endpointId}', CGI.escape(endpoint_id.to_s))

# query parameters
query_params = opts[:query_params] || {}
Expand Down
Loading