Skip to content

Commit 831c174

Browse files
committed
Merge remote-tracking branch 'origin/master' into jar-contributing-md
2 parents 59831e7 + ef7e6ee commit 831c174

11 files changed

+187
-8
lines changed

.github/workflows/ci.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ jobs:
4040

4141
test:
4242
name: Test (${{ matrix.ruby-version }})
43-
runs-on: ubuntu-latest
43+
# this is needed because our JRuby test version isnt supported on ubuntu-24 (which is now ubuntu-latest)
44+
runs-on: ubuntu-22.04
4445
strategy:
4546
matrix:
4647
ruby-version: [2.3, 2.4, 2.5, 2.6, 2.7, '3.0', 3.1, 3.2, '3.3', jruby-9.4.0.0, truffleruby-head]

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
# Changelog
2+
## 13.3.1 - 2025-01-13
3+
* [#1512](https://github.com/stripe/stripe-ruby/pull/1512) Import global configuration for options not available on StripeClient options
4+
* Fixes bug where `StripeClient` was not falling back to global options for options that are not available to be set per-client
5+
* [#1516](https://github.com/stripe/stripe-ruby/pull/1516) ThinEvent reason and livemode
6+
- Add `livemode` and optional `reason` fields to ThinEvent
7+
* [#1518](https://github.com/stripe/stripe-ruby/pull/1518) Pin ubuntu version in Test action
8+
* [#1508](https://github.com/stripe/stripe-ruby/pull/1508) Added pull request template
9+
210
## 13.3.0 - 2024-12-18
311
* [#1500](https://github.com/stripe/stripe-ruby/pull/1500) This release changes the pinned API version to `2024-12-18.acacia`.
412

VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
13.3.0
1+
13.3.1

lib/stripe.rb

+22
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,28 @@ module Stripe
7474
DEFAULT_UPLOAD_BASE = "https://files.stripe.com"
7575
DEFAULT_METER_EVENTS_BASE = "https://meter-events.stripe.com"
7676

77+
# Options that can be configured globally by users
78+
USER_CONFIGURABLE_GLOBAL_OPTIONS = Set.new(%i[
79+
api_key
80+
api_version
81+
stripe_account
82+
api_base
83+
uploads_base
84+
connect_base
85+
meter_events_base
86+
open_timeout
87+
read_timeout
88+
write_timeout
89+
proxy
90+
verify_ssl_certs
91+
ca_bundle_path
92+
log_level
93+
logger
94+
max_network_retries
95+
enable_telemetry
96+
client_id
97+
])
98+
7799
@app_info = nil
78100

79101
@config = Stripe::StripeConfiguration.setup

lib/stripe/stripe_client.rb

+6-1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ class StripeClient
1010

1111
# attr_readers: The end of the section generated from our OpenAPI spec
1212

13+
# For internal use only. Does not provide a stable API and may be broken
14+
# with future non-major changes.
15+
CLIENT_OPTIONS = Set.new(%i[api_key stripe_account stripe_context api_version api_base uploads_base connect_base meter_events_base client_id])
16+
1317
# Initializes a new StripeClient
1418
def initialize(api_key, # rubocop:todo Metrics/ParameterLists
1519
stripe_account: nil,
@@ -40,7 +44,8 @@ def initialize(api_key, # rubocop:todo Metrics/ParameterLists
4044
client_id: client_id,
4145
}.reject { |_k, v| v.nil? }
4246

43-
@requestor = APIRequestor.new(config_opts)
47+
config = StripeConfiguration.client_init(config_opts)
48+
@requestor = APIRequestor.new(config)
4449

4550
# top-level services: The beginning of the section generated from our OpenAPI spec
4651
@v1 = Stripe::V1Services.new(@requestor)

lib/stripe/stripe_configuration.rb

+21-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,25 @@ def self.setup
3737
end
3838
end
3939

40+
# Set options to the StripeClient configured options, if valid as a client option and provided
41+
# Otherwise, for user configurable global options, set them to the global configuration
42+
# For all other options, set them to the StripeConfiguration default value
43+
def self.client_init(config_opts)
44+
global_config = Stripe.config
45+
imported_options = USER_CONFIGURABLE_GLOBAL_OPTIONS - StripeClient::CLIENT_OPTIONS
46+
client_config = StripeConfiguration.setup do |instance|
47+
imported_options.each do |key|
48+
begin
49+
instance.public_send("#{key}=", global_config.public_send(key)) if global_config.respond_to?(key)
50+
rescue NotImplementedError => e
51+
# In Ruby <= 2.5, we can't set write_timeout on Net::HTTP, log an error and continue
52+
Util.log_error("Failed to set #{key} on client configuration: #{e}")
53+
end
54+
end
55+
end
56+
client_config.reverse_duplicate_merge(config_opts)
57+
end
58+
4059
# Create a new config based off an existing one. This is useful when the
4160
# caller wants to override the global configuration
4261
def reverse_duplicate_merge(hash)
@@ -68,7 +87,8 @@ def initialize
6887
@connect_base = DEFAULT_CONNECT_BASE
6988
@uploads_base = DEFAULT_UPLOAD_BASE
7089
@meter_events_base = DEFAULT_METER_EVENTS_BASE
71-
@base_addresses = { api: @api_base, connect: @connect_base, files: @uploads_base, events: @meter_events_base }
90+
@base_addresses = { api: @api_base, connect: @connect_base, files: @uploads_base,
91+
meter_events: @meter_events_base, }
7292
end
7393

7494
def log_level=(val)

lib/stripe/thin_event.rb

+22-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,26 @@
11
# frozen_string_literal: true
22

33
module Stripe
4+
class EventReasonRequest
5+
attr_reader :id, :idempotency_key
6+
7+
def initialize(event_reason_request_payload = {})
8+
@id = event_reason_request_payload[:id]
9+
@idempotency_key = event_reason_request_payload[:idempotency_key]
10+
end
11+
end
12+
13+
class EventReason
14+
attr_reader :type, :request
15+
16+
def initialize(event_reason_payload = {})
17+
@type = event_reason_payload[:type]
18+
@request = EventReasonRequest.new(event_reason_payload[:request])
19+
end
20+
end
21+
422
class ThinEvent
5-
attr_reader :id, :type, :created, :context, :related_object
23+
attr_reader :id, :type, :created, :context, :related_object, :livemode, :reason
624

725
def initialize(event_payload = {})
826
@id = event_payload[:id]
@@ -11,7 +29,9 @@ def initialize(event_payload = {})
1129
@context = event_payload[:context]
1230
@livemode = event_payload[:livemode]
1331
@related_object = event_payload[:related_object]
14-
@reason = event_payload[:reason]
32+
return if event_payload[:reason].nil?
33+
34+
@reason = EventReason.new(event_payload[:reason])
1535
end
1636
end
1737
end

lib/stripe/version.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# frozen_string_literal: true
22

33
module Stripe
4-
VERSION = "13.3.0"
4+
VERSION = "13.3.1"
55
end

test/stripe/stripe_client_test.rb

+26-1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class StripeClientTest < Test::Unit::TestCase
2020
@orig_api_key = Stripe.api_key
2121
@orig_stripe_account = Stripe.stripe_account
2222
@orig_open_timeout = Stripe.open_timeout
23+
@orig_api_version = Stripe.api_version
2324

2425
Stripe.api_key = "DONT_USE_THIS_KEY"
2526
Stripe.stripe_account = "DONT_USE_THIS_ACCOUNT"
@@ -30,6 +31,7 @@ class StripeClientTest < Test::Unit::TestCase
3031
Stripe.api_key = @orig_api_key
3132
Stripe.stripe_account = @orig_stripe_account
3233
Stripe.open_timeout = @orig_open_timeout
34+
Stripe.api_version = @orig_api_version
3335
end
3436

3537
should "use default config options" do
@@ -45,7 +47,6 @@ class StripeClientTest < Test::Unit::TestCase
4547
client = StripeClient.new("test_123")
4648
assert_equal "test_123", client.instance_variable_get(:@requestor).config.api_key
4749
assert_nil client.instance_variable_get(:@requestor).config.stripe_account
48-
assert_equal 30, client.instance_variable_get(:@requestor).config.open_timeout
4950
end
5051

5152
should "use client config options" do
@@ -67,6 +68,30 @@ class StripeClientTest < Test::Unit::TestCase
6768
assert_equal "2022-11-15", req.headers["Stripe-Version"]
6869
end
6970

71+
should "use global config options for options unavailable in client" do
72+
Stripe.api_key = "NOT_THIS_KEY"
73+
Stripe.stripe_account = "NOT_THIS_ACCOUNT"
74+
Stripe.api_version = "2022-11-15"
75+
client = StripeClient.new("test_123", stripe_account: "acct_123")
76+
# Imported from global options
77+
assert_equal 30_000, client.instance_variable_get(:@requestor).config.open_timeout
78+
# Not set in client options, not imported from global
79+
assert_equal client.instance_variable_get(:@requestor).config.api_base, Stripe::DEFAULT_API_BASE
80+
assert_equal client.instance_variable_get(:@requestor).config.api_version, Stripe::ApiVersion::CURRENT
81+
82+
req = nil
83+
stub_request(:get, "#{Stripe::DEFAULT_API_BASE}/v1/customers/cus_123")
84+
.with { |request| req = request }
85+
.to_return(body: JSON.generate(object: "customer"))
86+
87+
client.v1.customers.retrieve("cus_123")
88+
89+
# Set in client options
90+
assert_equal "Bearer test_123", req.headers["Authorization"]
91+
assert_equal "acct_123", req.headers["Stripe-Account"]
92+
assert_requested(:get, "#{Stripe::DEFAULT_API_BASE}/v1/customers/cus_123")
93+
end
94+
7095
should "request options overrides client config options" do
7196
client = StripeClient.new("test_123", stripe_version: "2022-11-15", stripe_account: "acct_123")
7297

test/stripe/stripe_configuration_test.rb

+44
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,50 @@ class StripeConfigurationTest < Test::Unit::TestCase
9797
end
9898
end
9999

100+
context "client_init" do
101+
setup do
102+
@client_opts = Hash[StripeClient::CLIENT_OPTIONS.map { |k| [k, nil] }] # rubocop:todo Style/HashConversion - necessary for Ruby <= 2.5
103+
@old_api_key = Stripe.api_key
104+
@old_stripe_account = Stripe.stripe_account
105+
@old_enable_telemetry = Stripe.instance_variable_get(:@enable_telemetry)
106+
@old_open_timeout = Stripe.open_timeout
107+
@old_uploads_base = Stripe.uploads_base
108+
end
109+
110+
teardown do
111+
Stripe.api_key = @old_api_key
112+
Stripe.stripe_account = @old_stripe_account
113+
Stripe.enable_telemetry = @old_enable_telemetry
114+
Stripe.open_timeout = @old_open_timeout
115+
Stripe.uploads_base = @old_uploads_base
116+
end
117+
118+
should "correctly set options for the client" do
119+
# mix of default, global, client options
120+
Stripe.api_key = "global_test_123"
121+
Stripe.stripe_account = "global_acct_123"
122+
Stripe.enable_telemetry = false
123+
Stripe.open_timeout = 30_000
124+
Stripe.uploads_base = "global_uploads_base.stripe.com"
125+
126+
@client_opts[:api_key] = "client_test_123"
127+
@client_opts[:stripe_account] = "client_acct_123"
128+
@client_opts[:uploads_base] = "client_uploads_base.stripe.com"
129+
@client_opts.reject! { |_k, v| v.nil? }
130+
131+
client_config = Stripe::StripeConfiguration.client_init(@client_opts)
132+
133+
assert_equal("client_test_123", client_config.api_key) # client api key
134+
assert_equal("client_acct_123", client_config.stripe_account) # client stripe account
135+
assert_equal(false, client_config.enable_telemetry) # global telemetry
136+
assert_equal(30_000, client_config.open_timeout) # global timeout
137+
assert_equal("client_uploads_base.stripe.com", client_config.base_addresses[:files]) # client uploads base
138+
assert_equal(Stripe::DEFAULT_API_BASE, client_config.base_addresses[:api]) # default api base
139+
assert_equal(ApiVersion::CURRENT, client_config.api_version) # default api version
140+
assert_equal(Stripe::DEFAULT_CA_BUNDLE_PATH, client_config.ca_bundle_path) # default ca bundle path
141+
end
142+
end
143+
100144
context "#max_network_retries=" do
101145
should "coerce the option into an integer" do
102146
config = Stripe::StripeConfiguration.setup

test/stripe/v2_event_test.rb

+34
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,26 @@ def retrieve_event(evt_id)
3636
},
3737
}.to_json
3838

39+
@v2_push_payload_with_livemode_and_reason = {
40+
"id" => "evt_234",
41+
"object" => "v2.core.event",
42+
"type" => "v1.billing.meter.error_report_triggered",
43+
"created" => "2022-02-15T00:27:45.330Z",
44+
"related_object" => {
45+
"id" => "mtr_123",
46+
"type" => "billing.meter",
47+
"url" => "/v1/billing/meters/mtr_123",
48+
},
49+
"livemode" => true,
50+
"reason" => {
51+
"type" => "a.b.c",
52+
"request" => {
53+
"id" => "r_123",
54+
"idempotency_key" => "key",
55+
},
56+
},
57+
}.to_json
58+
3959
@v2_pull_payload = {
4060
"id" => "evt_234",
4161
"object" => "v2.core.event",
@@ -76,6 +96,20 @@ def retrieve_event(evt_id)
7696
assert_equal "evt_234", event.id
7797
assert_equal "v1.billing.meter.error_report_triggered", event.type
7898
assert_equal "2022-02-15T00:27:45.330Z", event.created
99+
assert_nil event.reason
100+
end
101+
102+
should "parse v2 events with livemode and reason" do
103+
event = parse_signed_event(@v2_push_payload_with_livemode_and_reason)
104+
assert event.is_a?(Stripe::ThinEvent)
105+
assert_equal "evt_234", event.id
106+
assert_equal "v1.billing.meter.error_report_triggered", event.type
107+
assert_equal "2022-02-15T00:27:45.330Z", event.created
108+
assert_true event.livemode
109+
assert_not_nil event.reason
110+
assert_equal "a.b.c", event.reason.type
111+
assert_equal "r_123", event.reason.request.id
112+
assert_equal "key", event.reason.request.idempotency_key
79113
end
80114

81115
should "raise a JSON::ParserError from an invalid JSON payload" do

0 commit comments

Comments
 (0)