dnsimple 11.0.0 → 11.1.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: 4181725aaf336953ed62dc82cb74fe1d4457880f9fccf3940c817e27ffa559b5
4
- data.tar.gz: 11662d9a7780adbb47599e34a6e820c2b980c0be22ec79985557f4bd1801592c
3
+ metadata.gz: 31ae749f873b79c185866f4d4eb065ca98bcbcb956aefe9b2e105c7768edce8d
4
+ data.tar.gz: 7662580ca2df8c17507cc1f46e551cd65ac03b3c6a74a910ca38eaa8613c321d
5
5
  SHA512:
6
- metadata.gz: c4357613ee6e5c1b8d25a89a8ce6d61fa53c3369bf59ff9e33f5fce0fc800f31e5a0f0d4709726de2fb0f0c4bc7ec092a34c238d9b8fca28bdb722ad6cd2462b
7
- data.tar.gz: fa7726f50d6794b34ce537292d50b8050379751942201dad2e61ae246aed2ba5079841140b87ac6bd4494b724aeebc155cc59438f9f9693f69b8dc0c4742357f
6
+ metadata.gz: e1fd16b35b4fe0bce02df6e8a3af70eb9df5cc76c18c4b6e264e50f0c6b2efeac3631ed7cd76a25e6aaedc4a9fcfdf94e23a31f6f37f248cb49123c31f2ae170
7
+ data.tar.gz: b4e9842be063a37cd705bfe8ecf365b0cbd8dc315489f80b8e17290e8b96311d0adc836deffaff3151ea5379cd16d1c45503bfce827756a8aeb0cb8110c56acf
@@ -11,7 +11,7 @@ jobs:
11
11
 
12
12
  steps:
13
13
  - name: Wait for tests to succeed
14
- uses: lewagon/wait-on-check-action@v1.4.0
14
+ uses: lewagon/wait-on-check-action@v1.4.1
15
15
  with:
16
16
  ref: 'refs/heads/main'
17
17
  running-workflow-name: 'Release to RubyGems'
@@ -98,7 +98,7 @@ Naming/MemoizedInstanceVariableName:
98
98
  # to use simple ? methods.
99
99
  # Moreover, it's actually more efficient to not-use predicates:
100
100
  # https://github.com/bbatsov/rubocop/issues/3633
101
- Naming/PredicateName:
101
+ Naming/PredicatePrefix:
102
102
  Enabled: false
103
103
 
104
104
  # The team agreed decided to use exception.
data/CHANGELOG.md CHANGED
@@ -4,6 +4,10 @@ This project uses [Semantic Versioning 2.0.0](http://semver.org/).
4
4
 
5
5
  ## main
6
6
 
7
+ ## 11.1.0
8
+
9
+ - NEW: Added `Dnsimple::Client::ZonesRecords#batch_change_zone_records` to make changes to zone records in a batch. (dnsimple/dnsimple-ruby#434)
10
+
7
11
  ## 11.0.0
8
12
 
9
13
  - CHANGED: Removed `from` and `to` fields in `EmailForward`
@@ -156,6 +156,39 @@ module Dnsimple
156
156
  Dnsimple::Response.new(response, nil)
157
157
  end
158
158
 
159
+ # Updates a zone with a set of records (records to be created, edited or deleted), as an atomic batch operation.
160
+ #
161
+ # @see https://developer.dnsimple.com/v2/zones/records/batchChangeZoneRecords
162
+ #
163
+ # @example Create 2 A records in zone "example.com", update 1 record and delete 1 record.
164
+ # client.zones.batch_change_zone_records(1010, "example.com", { creates: [{ type: "A", content: "1.2.3.4", name: "ab" }, { type: "A", content: "2.3.4.5", name: "ab" }], updates: [{ id: 67622534, content: "3.2.3.40", name: "www" } }, deletes: [{ id: 67622509 })
165
+ #
166
+ # @param [Integer] account_id the account ID
167
+ # @param [String] zone_id the zone name
168
+ # @param attributes [Hash] Specifies the record creations and/or updates and/or deletions that should be performed as an atomic batch operation in the zone
169
+ # @option attributes [Array<Hash>] :creates (optional)
170
+ # @option attributes [Array<Hash>] :updates (optional)
171
+ # @option attributes [Array<Hash>] :deletes (optional)
172
+ # @param [Hash] options
173
+ # @return [Dnsimple::Response<Dnsimple::Struct::ZoneRecordsBatchChange>]
174
+ #
175
+ # @raise [Dnsimple::NotFoundError]
176
+ # @raise [Dnsimple::RequestError]
177
+ def batch_change_zone_records(account_id, zone_id, attributes, options = {})
178
+ response = client.post(Client.versioned("/%s/zones/%s/batch" % [account_id, zone_id]), attributes, options)
179
+
180
+ creates, updates, deletes = []
181
+ if response["data"]
182
+ creates_data = response["data"]["creates"] || []
183
+ creates = creates_data.map { |r| Struct::ZoneRecord.new(r) }
184
+ updates_data = response["data"]["updates"] || []
185
+ updates = updates_data.map { |r| Struct::ZoneRecord.new(r) }
186
+ deletes_data = response["data"]["deletes"] || []
187
+ deletes = deletes_data.map { |r| Struct::ZoneRecordId.new(r) }
188
+ end
189
+ Dnsimple::Response.new(response, Struct::ZoneRecordsBatchChange.new({ creates: creates, updates: updates, deletes: deletes }))
190
+ end
191
+
159
192
  end
160
193
  end
161
194
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dnsimple
4
+ module Struct
5
+ class ZoneRecordId < Base
6
+
7
+ # @return [Integer] The record ID in DNSimple.
8
+ attr_accessor :id
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dnsimple
4
+ module Struct
5
+ class ZoneRecordsBatchChange < Base
6
+
7
+ # @return [Array<ZoneRecord>]
8
+ attr_accessor :creates
9
+
10
+ # @return [Array<ZoneRecord>]
11
+ attr_accessor :updates
12
+
13
+ # @return [Array<ZoneRecordId>]
14
+ attr_accessor :deletes
15
+
16
+ end
17
+ end
18
+ end
@@ -51,6 +51,8 @@ require_relative "struct/vanity_name_server"
51
51
  require_relative "struct/whois_privacy"
52
52
  require_relative "struct/whois_privacy_renewal"
53
53
  require_relative "struct/zone"
54
+ require_relative "struct/zone_records_batch_change"
55
+ require_relative "struct/zone_record_id"
54
56
  require_relative "struct/zone_file"
55
57
  require_relative "struct/zone_distribution"
56
58
  require_relative "struct/webhook"
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Dnsimple
4
4
 
5
- VERSION = "11.0.0"
5
+ VERSION = "11.1.0"
6
6
 
7
7
  end
@@ -163,7 +163,7 @@ describe Dnsimple::Client, ".domains" do
163
163
  context "when the delegation signer record does not exist" do
164
164
  it "raises NotFoundError" do
165
165
  stub_request(:get, %r{/v2})
166
- .to_return(read_http_fixture("notfound-delegationsignerrecord.http"))
166
+ .to_return(read_http_fixture("notfound-delegationSignerRecord.http"))
167
167
 
168
168
  expect {
169
169
  subject.delegation_signer_record(account_id, domain_id, ds_record_id)
@@ -200,7 +200,7 @@ describe Dnsimple::Client, ".domains" do
200
200
  context "when the delegation signer record does not exist" do
201
201
  it "raises NotFoundError" do
202
202
  stub_request(:delete, %r{/v2})
203
- .to_return(read_http_fixture("notfound-delegationsignerrecord.http"))
203
+ .to_return(read_http_fixture("notfound-delegationSignerRecord.http"))
204
204
 
205
205
  expect {
206
206
  subject.delete_delegation_signer_record(account_id, domain_id, ds_record_id)
@@ -316,4 +316,99 @@ describe Dnsimple::Client, ".zones" do
316
316
  end
317
317
  end
318
318
 
319
+ describe "#batch_change_zone_records" do
320
+ let(:account_id) { 1010 }
321
+ let(:attributes) { { creates: [{ type: "A", content: "3.2.3.4", name: "ab" }, { type: "A", content: "4.2.3.4", name: "ab" }], updates: [{ id: 67622534, content: "3.2.3.40", name: "update1-1757049890" }, { id: 67622537, content: "5.2.3.40", name: "update2-1757049890" }], deletes: [{ id: 67622509 }, { id: 67622527 }] } }
322
+ let(:zone_id) { "example.com" }
323
+
324
+ before do
325
+ stub_request(:post, %r{/v2/#{account_id}/zones/#{zone_id}/batch$})
326
+ .to_return(read_http_fixture("batchChangeZoneRecords/success.http"))
327
+ end
328
+
329
+
330
+ it "builds the correct request" do
331
+ subject.batch_change_zone_records(account_id, zone_id, attributes)
332
+
333
+ expect(WebMock).to have_requested(:post, "https://api.dnsimple.test/v2/#{account_id}/zones/#{zone_id}/batch")
334
+ .with(body: attributes)
335
+ .with(headers: { "Accept" => "application/json" })
336
+ end
337
+
338
+ it "returns the result" do
339
+ response = subject.batch_change_zone_records(account_id, zone_id, attributes)
340
+ expect(response).to be_a(Dnsimple::Response)
341
+
342
+ result = response.data
343
+ expect(result).to be_a(Dnsimple::Struct::ZoneRecordsBatchChange)
344
+ expect(result.creates[0].id).to eq(67623409)
345
+ expect(result.creates[0].type).to eq(attributes.fetch(:creates)[0].fetch(:type))
346
+ expect(result.creates[0].name).to eq(attributes.fetch(:creates)[0].fetch(:name))
347
+ expect(result.creates[0].content).to eq(attributes.fetch(:creates)[0].fetch(:content))
348
+ expect(result.creates[0].regions).to eq(["global"])
349
+ expect(result.creates[1].id).to eq(67623410)
350
+ expect(result.updates[0].id).to eq(67622534)
351
+ expect(result.updates[0].type).to eq("A")
352
+ expect(result.updates[0].name).to eq(attributes.fetch(:updates)[0].fetch(:name))
353
+ expect(result.updates[0].content).to eq(attributes.fetch(:updates)[0].fetch(:content))
354
+ expect(result.updates[1].id).to eq(67622537)
355
+ expect(result.deletes[0].id).to eq(67622509)
356
+ expect(result.deletes[1].id).to eq(67622527)
357
+ end
358
+
359
+ context "when there are errors with creation" do
360
+ it "raises RequestError" do
361
+ stub_request(:post, %r{/v2/#{account_id}/zones/#{zone_id}/batch$})
362
+ .to_return(read_http_fixture("batchChangeZoneRecords/error_400_create_validation_failed.http"))
363
+
364
+ expect {
365
+ subject.batch_change_zone_records(account_id, zone_id, attributes)
366
+ }.to raise_error(Dnsimple::RequestError, "Validation failed") do |exception|
367
+ expect(exception.attribute_errors["creates"][0]["message"]).to eq("Validation failed")
368
+ expect(exception.attribute_errors["creates"][0]["index"]).to eq(0)
369
+ expect(exception.attribute_errors["creates"][0]["errors"]).to eq({ "record_type" => ["unsupported"] })
370
+ end
371
+ end
372
+ end
373
+
374
+ context "when there are errors with updates" do
375
+ it "raises RequestError" do
376
+ stub_request(:post, %r{/v2/#{account_id}/zones/#{zone_id}/batch$})
377
+ .to_return(read_http_fixture("batchChangeZoneRecords/error_400_update_validation_failed.http"))
378
+
379
+ expect {
380
+ subject.batch_change_zone_records(account_id, zone_id, attributes)
381
+ }.to raise_error(Dnsimple::RequestError, "Validation failed") do |exception|
382
+ expect(exception.attribute_errors["updates"][0]["message"]).to eq("Record not found ID=99999999")
383
+ expect(exception.attribute_errors["updates"][0]["index"]).to eq(0)
384
+ end
385
+ end
386
+ end
387
+
388
+ context "when there are errors with deletes" do
389
+ it "raises RequestError" do
390
+ stub_request(:post, %r{/v2/#{account_id}/zones/#{zone_id}/batch$})
391
+ .to_return(read_http_fixture("batchChangeZoneRecords/error_400_delete_validation_failed.http"))
392
+
393
+ expect {
394
+ subject.batch_change_zone_records(account_id, zone_id, attributes)
395
+ }.to raise_error(Dnsimple::RequestError, "Validation failed") do |exception|
396
+ expect(exception.attribute_errors["deletes"][0]["message"]).to eq("Record not found ID=67622509")
397
+ expect(exception.attribute_errors["deletes"][0]["index"]).to eq(0)
398
+ end
399
+ end
400
+ end
401
+
402
+ context "when the zone does not exist" do
403
+ it "raises NotFoundError" do
404
+ stub_request(:post, %r{/v2})
405
+ .to_return(read_http_fixture("notfound-zone.http"))
406
+
407
+ expect {
408
+ subject.batch_change_zone_records(account_id, zone_id, attributes)
409
+ }.to raise_error(Dnsimple::NotFoundError)
410
+ end
411
+ end
412
+ end
413
+
319
414
  end
@@ -0,0 +1,16 @@
1
+ HTTP/1.1 400 Bad Request
2
+ Server: nginx
3
+ Date: Tue, 23 Sep 2025 10:21:06 GMT
4
+ Content-Type: application/json; charset=utf-8
5
+ Content-Length: 137
6
+ Connection: keep-alive
7
+ X-RateLimit-Limit: 2400
8
+ X-RateLimit-Remaining: 2397
9
+ X-RateLimit-Reset: 1758626142
10
+ X-WORK-WITH-US: Love automation? So do we! https://dnsimple.com/jobs
11
+ Cache-Control: no-cache
12
+ X-Request-Id: 22761da9-ad02-4970-add5-e26602b09bb5
13
+ X-Runtime: 0.115194
14
+ Strict-Transport-Security: max-age=63072000
15
+
16
+ {"message":"Validation failed","errors":{"creates":[{"index":0,"message":"Validation failed","errors":{"record_type":["unsupported"]}}]}}
@@ -0,0 +1,15 @@
1
+ HTTP/1.1 400 Bad Request
2
+ server: nginx
3
+ date: Fri, 05 Sep 2025 06:50:48 GMT
4
+ content-type: application/json; charset=utf-8
5
+ content-length: 107
6
+ X-RateLimit-Limit: 2400
7
+ X-RateLimit-Remaining: 2390
8
+ X-RateLimit-Reset: 1757058040
9
+ x-work-with-us: Love automation? So do we! https://dnsimple.com/jobs
10
+ cache-control: no-cache
11
+ x-request-id: 254988cd-401b-4a32-b5d8-c25502573c9a
12
+ x-runtime: 0.105704
13
+ strict-transport-security: max-age=63072000
14
+
15
+ {"message":"Validation failed","errors":{"deletes":[{"index":0,"message":"Record not found ID=67622509"}]}}
@@ -0,0 +1,15 @@
1
+ HTTP/1.1 400 Bad Request
2
+ server: nginx
3
+ date: Fri, 05 Sep 2025 06:52:30 GMT
4
+ content-type: application/json; charset=utf-8
5
+ content-length: 107
6
+ X-RateLimit-Limit: 2400
7
+ X-RateLimit-Remaining: 2388
8
+ X-RateLimit-Reset: 1757058040
9
+ x-work-with-us: Love automation? So do we! https://dnsimple.com/jobs
10
+ cache-control: no-cache
11
+ x-request-id: e042a192-69de-46b5-9ea0-add647a9b20a
12
+ x-runtime: 0.170298
13
+ strict-transport-security: max-age=63072000
14
+
15
+ {"message":"Validation failed","errors":{"updates":[{"index":0,"message":"Record not found ID=99999999"}]}}
@@ -0,0 +1,16 @@
1
+ HTTP/1.1 200 OK
2
+ server: nginx
3
+ date: Fri, 05 Sep 2025 05:25:01 GMT
4
+ content-type: application/json; charset=utf-8
5
+ content-length: 1080
6
+ X-RateLimit-Limit: 2400
7
+ X-RateLimit-Remaining: 2399
8
+ X-RateLimit-Reset: 1757053501
9
+ x-work-with-us: Love automation? So do we! https://dnsimple.com/jobs
10
+ etag: W/"0d9f98e87eccabb6c8045c7fd0b61e5e"
11
+ cache-control: max-age=0, private, must-revalidate
12
+ x-request-id: f331c43b-7f06-4b1f-90a1-e88efee10c1c
13
+ x-runtime: 0.334890
14
+ strict-transport-security: max-age=63072000
15
+
16
+ {"data":{"creates":[{"id":67623409,"zone_id":"example.com","parent_id":null,"name":"ab","content":"3.2.3.4","ttl":3600,"priority":null,"type":"A","regions":["global"],"system_record":false,"created_at":"2025-09-05T05:25:00Z","updated_at":"2025-09-05T05:25:00Z"},{"id":67623410,"zone_id":"example.com","parent_id":null,"name":"ab","content":"4.2.3.4","ttl":3600,"priority":null,"type":"A","regions":["global"],"system_record":false,"created_at":"2025-09-05T05:25:00Z","updated_at":"2025-09-05T05:25:00Z"}],"updates":[{"id":67622534,"zone_id":"example.com","parent_id":null,"name":"update1-1757049890","content":"3.2.3.40","ttl":3600,"priority":null,"type":"A","regions":["global"],"system_record":false,"created_at":"2025-09-05T04:40:15Z","updated_at":"2025-09-05T05:25:00Z"},{"id":67622537,"zone_id":"example.com","parent_id":null,"name":"update2-1757049890","content":"5.2.3.40","ttl":3600,"priority":null,"type":"A","regions":["global"],"system_record":false,"created_at":"2025-09-05T04:40:22Z","updated_at":"2025-09-05T05:25:00Z"}],"deletes":[{"id":67622509},{"id":67622527}]}}
@@ -4,6 +4,9 @@ Date: Sun, 18 Feb 2024 10:48:05 GMT
4
4
  Content-Type: application/json
5
5
  Content-Length: 120
6
6
  Connection: keep-alive
7
+ X-RateLimit-Limit: 2400
8
+ X-RateLimit-Remaining: 2398
9
+ X-RateLimit-Reset: 1547125899
7
10
  X-WORK-WITH-US: Love automation? So do we! https://dnsimple.com/jobs
8
11
  Cache-Control: no-cache
9
12
  X-Request-Id: 2a8d691f-f47e-4d41-9916-eba67e683914
@@ -16,4 +19,4 @@ X-Permitted-Cross-Domain-Policies: none
16
19
  Content-Security-Policy: frame-ancestors 'none'
17
20
  Strict-Transport-Security: max-age=63072000
18
21
 
19
- {"data":{"id":43,"domain_id":214,"state":"new","created_at":"2024-02-14T14:40:42Z","updated_at":"2024-02-14T14:40:42Z"}}
22
+ {"data":{"id":43,"domain_id":214,"state":"new","created_at":"2024-02-14T14:40:42Z","updated_at":"2024-02-14T14:40:42Z"}}
@@ -4,6 +4,9 @@ Date: Sun, 18 Feb 2024 10:46:17 GMT
4
4
  Content-Type: application/json
5
5
  Content-Length: 120
6
6
  Connection: keep-alive
7
+ X-RateLimit-Limit: 2400
8
+ X-RateLimit-Remaining: 2398
9
+ X-RateLimit-Reset: 1547125899
7
10
  X-WORK-WITH-US: Love automation? So do we! https://dnsimple.com/jobs
8
11
  Cache-Control: no-cache
9
12
  X-Request-Id: 3bf33ae7-22f2-473c-8e39-8738d2bcce89
@@ -16,4 +19,4 @@ X-Permitted-Cross-Domain-Policies: none
16
19
  Content-Security-Policy: frame-ancestors 'none'
17
20
  Strict-Transport-Security: max-age=63072000
18
21
 
19
- {"data":{"id":43,"domain_id":214,"state":"new","created_at":"2024-02-14T14:40:42Z","updated_at":"2024-02-14T14:40:42Z"}}
22
+ {"data":{"id":43,"domain_id":214,"state":"new","created_at":"2024-02-14T14:40:42Z","updated_at":"2024-02-14T14:40:42Z"}}
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dnsimple
3
3
  version: !ruby/object:Gem::Version
4
- version: 11.0.0
4
+ version: 11.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - DNSimple
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-08-20 00:00:00.000000000 Z
11
+ date: 2025-09-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -184,6 +184,8 @@ files:
184
184
  - lib/dnsimple/struct/zone_distribution.rb
185
185
  - lib/dnsimple/struct/zone_file.rb
186
186
  - lib/dnsimple/struct/zone_record.rb
187
+ - lib/dnsimple/struct/zone_record_id.rb
188
+ - lib/dnsimple/struct/zone_records_batch_change.rb
187
189
  - lib/dnsimple/version.rb
188
190
  - spec/dnsimple/client/accounts_spec.rb
189
191
  - spec/dnsimple/client/billing_spec.rb
@@ -227,6 +229,10 @@ files:
227
229
  - spec/fixtures.http/applyTemplate/success.http
228
230
  - spec/fixtures.http/authorizeDomainTransferOut/success.http
229
231
  - spec/fixtures.http/badgateway.http
232
+ - spec/fixtures.http/batchChangeZoneRecords/error_400_create_validation_failed.http
233
+ - spec/fixtures.http/batchChangeZoneRecords/error_400_delete_validation_failed.http
234
+ - spec/fixtures.http/batchChangeZoneRecords/error_400_update_validation_failed.http
235
+ - spec/fixtures.http/batchChangeZoneRecords/success.http
230
236
  - spec/fixtures.http/cancelDomainTransfer/success.http
231
237
  - spec/fixtures.http/changeDomainDelegation/success.http
232
238
  - spec/fixtures.http/changeDomainDelegationFromVanity/success.http
@@ -343,7 +349,7 @@ files:
343
349
  - spec/fixtures.http/method-not-allowed.http
344
350
  - spec/fixtures.http/notfound-certificate.http
345
351
  - spec/fixtures.http/notfound-contact.http
346
- - spec/fixtures.http/notfound-delegationsignerrecord.http
352
+ - spec/fixtures.http/notfound-delegationSignerRecord.http
347
353
  - spec/fixtures.http/notfound-domain.http
348
354
  - spec/fixtures.http/notfound-domainpush.http
349
355
  - spec/fixtures.http/notfound-emailforward.http