contentstack 0.9.2 → 0.10.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 +4 -4
- data/CHANGELOG.md +7 -0
- data/Gemfile.lock +2 -2
- data/lib/contentstack/api.rb +48 -8
- data/lib/contentstack/entry.rb +20 -0
- data/lib/contentstack/query.rb +21 -0
- data/lib/contentstack/version.rb +1 -1
- data/spec/variants_spec.rb +97 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7e776d17a2fda85c9e2451aac3c798418b63a0866e0dbff1f6a45ecf35a881af
|
|
4
|
+
data.tar.gz: 55df7efc6ec43bfb3a1e500a2c28ecda534bbe7e9211f1cad62e419f509c35cf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0b19d4521e9d5451bf87f2c6ac385c477a3dcdab171b25c5f1047896f324e64c4bc60085c6cdf8e6cc006d46b4f752351aaf1b42518ae8285b2ed0725987a49a
|
|
7
|
+
data.tar.gz: 057fa0d575a8ae98de2d28f5ce382c1913e0099e3adc128ba2c36cb895d88c9651932f1df06cea8a3bddf158f31d6fc243656d2cbac3fbe4ab36bba2156a55c8
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
## CHANGELOG
|
|
2
2
|
|
|
3
|
+
## Version 0.10.0
|
|
4
|
+
### Date: 27th-July-2026
|
|
5
|
+
### Features
|
|
6
|
+
- Added `variants(variant_uids, branch_name)` on `Contentstack::Entry` and `Contentstack::Query` to fetch entry variants with optional per-request branch scoping. Requests send the `x-cs-variant-uid` header (comma-separated UIDs) and respect stack-level or per-call branch.
|
|
7
|
+
|
|
8
|
+
------------------------------------------------
|
|
9
|
+
|
|
3
10
|
## Version 0.9.2
|
|
4
11
|
### Date: 6th-July-2026
|
|
5
12
|
### Fix
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
contentstack (0.
|
|
4
|
+
contentstack (0.10.0)
|
|
5
5
|
activesupport (>= 3.2)
|
|
6
6
|
contentstack_utils (~> 1.2)
|
|
7
7
|
|
|
@@ -119,7 +119,7 @@ CHECKSUMS
|
|
|
119
119
|
bigdecimal (4.1.2) sha256=53d217666027eab4280346fba98e7d5b66baaae1b9c3c1c0ffe89d48188a3fbd
|
|
120
120
|
concurrent-ruby (1.3.7) sha256=4412caec3a5ea2e5fdc52076724c071a81f2c0593d83b2ac8cbb8ca63b3151b0
|
|
121
121
|
connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a
|
|
122
|
-
contentstack (0.
|
|
122
|
+
contentstack (0.10.0)
|
|
123
123
|
contentstack_utils (1.2.3) sha256=cf2f5f996eb487559fd2d7d48a99262710f53dec62c84c6e325b9a598cd31ba7
|
|
124
124
|
crack (1.0.1) sha256=ff4a10390cd31d66440b7524eb1841874db86201d5b70032028553130b6d4c7e
|
|
125
125
|
diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962
|
data/lib/contentstack/api.rb
CHANGED
|
@@ -73,7 +73,51 @@ module Contentstack
|
|
|
73
73
|
fetch_retry(path, query)
|
|
74
74
|
end
|
|
75
75
|
|
|
76
|
+
def self.validate_variant_uids!(variant_uids)
|
|
77
|
+
if variant_uids.nil? || (variant_uids.respond_to?(:empty?) && variant_uids.empty?)
|
|
78
|
+
raise Contentstack::Error.new("Variant UID(s) are required. Provide a variant UID or an array of variant UIDs.")
|
|
79
|
+
end
|
|
80
|
+
unless variant_uids.is_a?(String) || variant_uids.is_a?(Array)
|
|
81
|
+
raise Contentstack::Error.new("Variant UID(s) must be a String or Array of Strings.")
|
|
82
|
+
end
|
|
83
|
+
if variant_uids.is_a?(Array) && variant_uids.any? { |uid| !uid.is_a?(String) || uid.empty? }
|
|
84
|
+
raise Contentstack::Error.new("Variant UID(s) must be a String or Array of Strings.")
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
76
88
|
private
|
|
89
|
+
def self.prepare_query(q)
|
|
90
|
+
q = (q || {}).dup
|
|
91
|
+
variant_uids = q.delete(:variant_uids)
|
|
92
|
+
branch_override = q.delete(:branch)
|
|
93
|
+
[q, variant_uids, branch_override]
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def self.format_variant_uids(variant_uids)
|
|
97
|
+
return nil if variant_uids.nil?
|
|
98
|
+
|
|
99
|
+
case variant_uids
|
|
100
|
+
when String
|
|
101
|
+
variant_uids.strip
|
|
102
|
+
when Array
|
|
103
|
+
variant_uids.map(&:to_s).reject(&:empty?).join(', ')
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def self.resolve_branch(branch_override)
|
|
108
|
+
branch = branch_override
|
|
109
|
+
branch = @branch if branch.nil? || branch.to_s.empty?
|
|
110
|
+
branch
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def self.apply_variant_headers(params, variant_uids, branch_override)
|
|
114
|
+
formatted = format_variant_uids(variant_uids)
|
|
115
|
+
params["x-cs-variant-uid"] = formatted if formatted && !formatted.empty?
|
|
116
|
+
|
|
117
|
+
branch = resolve_branch(branch_override)
|
|
118
|
+
params["branch"] = branch if !branch.nil? && !branch.empty?
|
|
119
|
+
params
|
|
120
|
+
end
|
|
77
121
|
def self.fetch_retry(path, query=nil, count=0)
|
|
78
122
|
response = send_request(path, query)
|
|
79
123
|
if @errorRetry.include?(response["status_code"].to_i)
|
|
@@ -90,7 +134,7 @@ module Contentstack
|
|
|
90
134
|
end
|
|
91
135
|
|
|
92
136
|
def self.send_request(path, q=nil)
|
|
93
|
-
q
|
|
137
|
+
q, variant_uids, branch_override = prepare_query(q)
|
|
94
138
|
|
|
95
139
|
q.merge!(@headers)
|
|
96
140
|
|
|
@@ -103,9 +147,7 @@ module Contentstack
|
|
|
103
147
|
"x-user-agent" => "ruby-sdk/#{Contentstack::VERSION}",
|
|
104
148
|
"read_timeout" => @timeout
|
|
105
149
|
}
|
|
106
|
-
|
|
107
|
-
params["branch"] = @branch
|
|
108
|
-
end
|
|
150
|
+
apply_variant_headers(params, variant_uids, branch_override)
|
|
109
151
|
|
|
110
152
|
if @proxy_details.present? && @proxy_details[:url].present? && @proxy_details[:port].present? && @proxy_details[:username].empty? && @proxy_details[:password].empty?
|
|
111
153
|
params["proxy"] = URI.parse("http://#{@proxy_details[:url]}:#{@proxy_details[:port]}/").to_s
|
|
@@ -130,7 +172,7 @@ module Contentstack
|
|
|
130
172
|
end
|
|
131
173
|
|
|
132
174
|
def self.send_preview_request(path, q=nil)
|
|
133
|
-
q
|
|
175
|
+
q, variant_uids, branch_override = prepare_query(q)
|
|
134
176
|
|
|
135
177
|
q.merge!({live_preview: (!@live_preview.key?(:live_preview) ? 'init' : @live_preview[:live_preview]),})
|
|
136
178
|
|
|
@@ -143,9 +185,7 @@ module Contentstack
|
|
|
143
185
|
"x-user-agent" => "ruby-sdk/#{Contentstack::VERSION}",
|
|
144
186
|
"read_timeout" => @timeout
|
|
145
187
|
}
|
|
146
|
-
|
|
147
|
-
params["branch"] = @branch
|
|
148
|
-
end
|
|
188
|
+
apply_variant_headers(params, variant_uids, branch_override)
|
|
149
189
|
|
|
150
190
|
if @proxy_details.present? && @proxy_details[:url].present? && @proxy_details[:port].present? && @proxy_details[:username].empty? && @proxy_details[:password].empty?
|
|
151
191
|
params["proxy"] = URI.parse("http://#{@proxy_details[:url]}:#{@proxy_details[:port]}/").to_s
|
data/lib/contentstack/entry.rb
CHANGED
|
@@ -180,6 +180,26 @@ module Contentstack
|
|
|
180
180
|
self
|
|
181
181
|
end
|
|
182
182
|
|
|
183
|
+
# Scope the entry request to one or more entry variants, optionally on a branch.
|
|
184
|
+
#
|
|
185
|
+
# @param [String, Array<String>] variant_uids A variant UID, or an array of variant UIDs
|
|
186
|
+
# @param [String] branch_name Branch name to scope the request (overrides stack-level branch)
|
|
187
|
+
#
|
|
188
|
+
# Example
|
|
189
|
+
#
|
|
190
|
+
# @entry = @stack.content_type('home_page').entry(entry_uid)
|
|
191
|
+
# @entry.variants('xyz', 'branch_name').fetch
|
|
192
|
+
#
|
|
193
|
+
# @entry = @stack.content_type('home_page').entry(entry_uid)
|
|
194
|
+
# @entry.variants(['variant1', 'variant2'], 'branch_name').fetch
|
|
195
|
+
#
|
|
196
|
+
# @return [Contentstack::Entry]
|
|
197
|
+
def variants(variant_uids, branch_name = nil)
|
|
198
|
+
API.validate_variant_uids!(variant_uids)
|
|
199
|
+
@query[:variant_uids] = variant_uids
|
|
200
|
+
@query[:branch] = branch_name if branch_name.is_a?(String) && !branch_name.empty?
|
|
201
|
+
self
|
|
202
|
+
end
|
|
183
203
|
|
|
184
204
|
# Include Embedded Objects (Entries and Assets) along with entry/entries details.
|
|
185
205
|
#
|
data/lib/contentstack/query.rb
CHANGED
|
@@ -552,6 +552,27 @@ module Contentstack
|
|
|
552
552
|
self
|
|
553
553
|
end
|
|
554
554
|
|
|
555
|
+
# Scope the entries request to one or more entry variants, optionally on a branch.
|
|
556
|
+
#
|
|
557
|
+
# @param [String, Array<String>] variant_uids A variant UID, or an array of variant UIDs
|
|
558
|
+
# @param [String] branch_name Branch name to scope the request (overrides stack-level branch)
|
|
559
|
+
#
|
|
560
|
+
# Example
|
|
561
|
+
#
|
|
562
|
+
# @query = @stack.content_type('home_page').query
|
|
563
|
+
# @query.variants('xyz', 'branch_name').fetch
|
|
564
|
+
#
|
|
565
|
+
# @query = @stack.content_type('home_page').query
|
|
566
|
+
# @query.variants(['variant1', 'variant2'], 'branch_name').fetch
|
|
567
|
+
#
|
|
568
|
+
# @return [Contentstack::Query]
|
|
569
|
+
def variants(variant_uids, branch_name = nil)
|
|
570
|
+
API.validate_variant_uids!(variant_uids)
|
|
571
|
+
@query[:variant_uids] = variant_uids
|
|
572
|
+
@query[:branch] = branch_name if branch_name.is_a?(String) && !branch_name.empty?
|
|
573
|
+
self
|
|
574
|
+
end
|
|
575
|
+
|
|
555
576
|
# Include Embedded Objects (Entries and Assets) along with entry/entries details.
|
|
556
577
|
#
|
|
557
578
|
# Example
|
data/lib/contentstack/version.rb
CHANGED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe 'entry variants' do
|
|
4
|
+
let(:client) { create_client }
|
|
5
|
+
let(:branch_client) { create_client(ENV['DELIVERY_TOKEN'], ENV['API_KEY'], ENV['ENVIRONMENT'], { branch: 'stack_branch' }) }
|
|
6
|
+
let(:entry_uid) { 'uid' }
|
|
7
|
+
let(:category_entry) { client.content_type('category').entry(entry_uid) }
|
|
8
|
+
let(:category_query) { client.content_type('category').query }
|
|
9
|
+
|
|
10
|
+
describe Contentstack::Entry do
|
|
11
|
+
it 'stores variant UID and branch on the query' do
|
|
12
|
+
entry = category_entry.variants('variant1', 'branch_name')
|
|
13
|
+
expect(entry.query[:variant_uids]).to eq 'variant1'
|
|
14
|
+
expect(entry.query[:branch]).to eq 'branch_name'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'stores multiple variant UIDs' do
|
|
18
|
+
entry = category_entry.variants(['variant1', 'variant2'], 'branch_name')
|
|
19
|
+
expect(entry.query[:variant_uids]).to eq ['variant1', 'variant2']
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'raises when variant UIDs are missing' do
|
|
23
|
+
expect { category_entry.variants(nil) }.to raise_error(Contentstack::Error, /Variant UID/)
|
|
24
|
+
expect { category_entry.variants([]) }.to raise_error(Contentstack::Error, /Variant UID/)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'raises when variant UIDs are invalid' do
|
|
28
|
+
expect { category_entry.variants(123) }.to raise_error(Contentstack::Error, /String or Array/)
|
|
29
|
+
expect { category_entry.variants(['']) }.to raise_error(Contentstack::Error, /String or Array/)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
describe Contentstack::Query do
|
|
34
|
+
it 'stores variant UID and branch on the query' do
|
|
35
|
+
query = category_query.variants('variant1', 'branch_name')
|
|
36
|
+
expect(query.query[:variant_uids]).to eq 'variant1'
|
|
37
|
+
expect(query.query[:branch]).to eq 'branch_name'
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
describe 'HTTP headers' do
|
|
42
|
+
it 'sends x-cs-variant-uid and branch for a single entry fetch' do
|
|
43
|
+
stub = stub_request(:get, /cdn\.contentstack\.io\/v3\/content_types\/category\/entries\/uid/).
|
|
44
|
+
with { |req|
|
|
45
|
+
req.headers['X-Cs-Variant-Uid'] == 'variant1' &&
|
|
46
|
+
req.headers['Branch'] == 'branch_name'
|
|
47
|
+
}.
|
|
48
|
+
to_return(status: 200, body: File.read(File.dirname(__FILE__) + '/fixtures/category_entry.json'), headers: {})
|
|
49
|
+
|
|
50
|
+
category_entry.variants('variant1', 'branch_name').fetch
|
|
51
|
+
expect(stub).to have_been_requested
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'sends comma-separated variant UIDs for multiple variants' do
|
|
55
|
+
stub = stub_request(:get, /cdn\.contentstack\.io\/v3\/content_types\/category\/entries\/uid/).
|
|
56
|
+
with { |req| req.headers['X-Cs-Variant-Uid'] == 'variant1, variant2' }.
|
|
57
|
+
to_return(status: 200, body: File.read(File.dirname(__FILE__) + '/fixtures/category_entry.json'), headers: {})
|
|
58
|
+
|
|
59
|
+
category_entry.variants(['variant1', 'variant2'], 'branch_name').fetch
|
|
60
|
+
expect(stub).to have_been_requested
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it 'sends x-cs-variant-uid and branch for an entries query' do
|
|
64
|
+
stub = stub_request(:get, /cdn\.contentstack\.io\/v3\/content_types\/category\/entries/).
|
|
65
|
+
with { |req|
|
|
66
|
+
!req.uri.path.include?('/entries/uid') &&
|
|
67
|
+
req.headers['X-Cs-Variant-Uid'] == 'variant1' &&
|
|
68
|
+
req.headers['Branch'] == 'branch_name'
|
|
69
|
+
}.
|
|
70
|
+
to_return(status: 200, body: File.read(File.dirname(__FILE__) + '/fixtures/category_entry_collection_without_count.json'), headers: {})
|
|
71
|
+
|
|
72
|
+
category_query.variants('variant1', 'branch_name').fetch
|
|
73
|
+
expect(stub).to have_been_requested
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it 'uses stack-level branch when variants branch is omitted' do
|
|
77
|
+
stub = stub_request(:get, /cdn\.contentstack\.io\/v3\/content_types\/category\/entries\/uid/).
|
|
78
|
+
with { |req|
|
|
79
|
+
req.headers['X-Cs-Variant-Uid'] == 'variant1' &&
|
|
80
|
+
req.headers['Branch'] == 'stack_branch'
|
|
81
|
+
}.
|
|
82
|
+
to_return(status: 200, body: File.read(File.dirname(__FILE__) + '/fixtures/category_entry.json'), headers: {})
|
|
83
|
+
|
|
84
|
+
branch_client.content_type('category').entry(entry_uid).variants('variant1').fetch
|
|
85
|
+
expect(stub).to have_been_requested
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it 'does not add variant headers when variants is not chained' do
|
|
89
|
+
stub = stub_request(:get, /cdn\.contentstack\.io\/v3\/content_types\/category\/entries\/uid/).
|
|
90
|
+
with { |req| req.headers['X-Cs-Variant-Uid'].nil? }.
|
|
91
|
+
to_return(status: 200, body: File.read(File.dirname(__FILE__) + '/fixtures/category_entry.json'), headers: {})
|
|
92
|
+
|
|
93
|
+
category_entry.fetch
|
|
94
|
+
expect(stub).to have_been_requested
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: contentstack
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.10.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Contentstack
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-07-
|
|
11
|
+
date: 2026-07-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -167,6 +167,7 @@ files:
|
|
|
167
167
|
- spec/spec_helper.rb
|
|
168
168
|
- spec/support/load_test_env.rb
|
|
169
169
|
- spec/sync_spec.rb
|
|
170
|
+
- spec/variants_spec.rb
|
|
170
171
|
homepage: https://github.com/contentstack/contentstack-ruby
|
|
171
172
|
licenses:
|
|
172
173
|
- MIT
|