Skip to content

Commit b7e7ae4

Browse files
Merge branch 'master' into muzahidul-opti-patch-2
2 parents c91f0a4 + 64d659f commit b7e7ae4

File tree

12 files changed

+159
-53
lines changed

12 files changed

+159
-53
lines changed

.github/workflows/integration_tests.yml

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,6 @@ on:
55
secrets:
66
CI_USER_TOKEN:
77
required: true
8-
TRAVIS_COM_TOKEN:
9-
required: true
10-
118
jobs:
129
integration_tests:
1310
runs-on: ubuntu-latest
@@ -16,8 +13,8 @@ jobs:
1613
with:
1714
# You should create a personal access token and store it in your repository
1815
token: ${{ secrets.CI_USER_TOKEN }}
19-
repository: 'optimizely/travisci-tools'
20-
path: 'home/runner/travisci-tools'
16+
repository: 'optimizely/ci-helper-tools'
17+
path: 'home/runner/ci-helper-tools'
2118
ref: 'master'
2219
- name: set SDK Branch if PR
2320
env:
@@ -31,7 +28,6 @@ jobs:
3128
if: ${{ github.event_name != 'pull_request' }}
3229
run: |
3330
echo "SDK_BRANCH=$REF_NAME" >> $GITHUB_ENV
34-
echo "TRAVIS_BRANCH=$REF_NAME" >> $GITHUB_ENV
3531
- name: Trigger build
3632
env:
3733
SDK: swift
@@ -41,14 +37,12 @@ jobs:
4137
GITHUB_TOKEN: ${{ secrets.CI_USER_TOKEN }}
4238
EVENT_TYPE: ${{ github.event_name }}
4339
GITHUB_CONTEXT: ${{ toJson(github) }}
44-
#REPO_SLUG: ${{ github.repository }}
4540
PULL_REQUEST_SLUG: ${{ github.repository }}
4641
UPSTREAM_REPO: ${{ github.repository }}
4742
PULL_REQUEST_SHA: ${{ github.event.pull_request.head.sha }}
4843
PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
4944
UPSTREAM_SHA: ${{ github.sha }}
50-
TOKEN: ${{ secrets.TRAVIS_COM_TOKEN }}
5145
EVENT_MESSAGE: ${{ github.event.message }}
5246
HOME: 'home/runner'
5347
run: |
54-
home/runner/travisci-tools/trigger-script-with-status-update.sh
48+
home/runner/ci-helper-tools/trigger-script-with-status-update.sh

.github/workflows/swift.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ on:
1717
description: release
1818

1919
env:
20-
VERSION: 5.0.0
20+
VERSION: 5.1.0
2121

2222
jobs:
2323

@@ -29,7 +29,6 @@ jobs:
2929
uses: optimizely/swift-sdk/.github/workflows/integration_tests.yml@master
3030
secrets:
3131
CI_USER_TOKEN: ${{ secrets.CI_USER_TOKEN }}
32-
TRAVIS_COM_TOKEN: ${{ secrets.TRAVIS_COM_TOKEN }}
3332

3433
lint:
3534
runs-on: macos-13

.github/workflows/unit_tests.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,27 +19,27 @@ jobs:
1919
# - see "https://github.com/actions/runner-images/blob/main/images/macos/macos-11-Readme.md" for installed macOS, xcode and simulator versions.
2020
include:
2121
- os: 16.1
22-
device: "iPhone 12"
22+
device: "iPhone 14"
2323
scheme: "OptimizelySwiftSDK-iOS"
2424
test_sdk: "iphonesimulator"
2525
platform: "iOS Simulator"
2626
os_type: "iOS"
2727
simulator_xcode_version: 14.1
28-
- os: 15.5
29-
device: "iPhone 12"
28+
- os: 16.2
29+
device: "iPhone 14"
3030
scheme: "OptimizelySwiftSDK-iOS"
3131
test_sdk: "iphonesimulator"
3232
platform: "iOS Simulator"
3333
os_type: "iOS"
34-
simulator_xcode_version: 13.4.1
35-
- os: 15.5
34+
simulator_xcode_version: 14.2
35+
- os: 16.4
3636
# good to have tests with older OS versions, but it looks like this is min OS+xcode versions supported by github actions
37-
device: "iPad Air (4th generation)"
37+
device: "iPad Air (5th generation)"
3838
scheme: "OptimizelySwiftSDK-iOS"
3939
test_sdk: "iphonesimulator"
4040
platform: "iOS Simulator"
4141
os_type: "iOS"
42-
simulator_xcode_version: 13.4.1
42+
simulator_xcode_version: 14.3.1
4343
- os: 16.1
4444
device: "Apple TV"
4545
scheme: "OptimizelySwiftSDK-tvOS"
@@ -85,7 +85,7 @@ jobs:
8585
# - to find pre-installed xcode version, run this:
8686
##ls /Applications/
8787
# - to find supported simulator os versions, run this (and find simulator with non-error "datapath")
88-
##xcrun simctl list --json devices
88+
# xcrun simctl list --json devices
8989
9090
# switch to the target xcode version
9191
sudo xcode-select -switch /Applications/Xcode_$SIMULATOR_XCODE_VERSION.app

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Optimizely Swift SDK Changelog
22

3+
## 5.1.0
4+
February 4th, 2025
5+
6+
### Functionality Enhancement
7+
* Add support for nested event tags ([#570](https://github.com/optimizely/swift-sdk/pull/570)).
8+
39
## 5.0.0
410
November 25th, 2024
511

OptimizelySwiftSDK.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Pod::Spec.new do |s|
22
s.name = "OptimizelySwiftSDK"
33
s.module_name = "Optimizely"
4-
s.version = "5.0.0"
4+
s.version = "5.1.0"
55
s.summary = "Optimizely experiment framework for iOS/tvOS/watchOS"
66
s.homepage = "https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs"
77
s.license = { :type => "Apache License, Version 2.0", :file => "LICENSE" }

README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ If you have a name conflict with other swift packages when you add the Optimizel
3939
#### CocoaPods
4040
1. Add the following lines to the _Podfile_:<pre>
4141
```use_frameworks!```
42-
```pod 'OptimizelySwiftSDK', '~> 5.0.0'```
42+
```pod 'OptimizelySwiftSDK', '~> 5.1.0'```
4343
</pre>
4444

4545
2. Run the following command: <pre>``` pod install ```</pre>
@@ -130,5 +130,4 @@ Used to enforce Swift style and conventions.
130130

131131
- React - https://github.com/optimizely/react-sdk
132132

133-
- Ruby - https://github.com/optimizely/ruby-sdk
134-
-
133+
- Ruby - https://github.com/optimizely/ruby-sdk

Sources/Data Model/Audience/AttributeValue.swift

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,15 @@
1717
import Foundation
1818

1919
enum AttributeValue: Codable, Equatable, CustomStringConvertible {
20+
typealias AttrArray = Array<AttributeValue>
21+
typealias AttrDictionary = [String : AttributeValue]
22+
2023
case string(String)
2124
case int(Int64) // supported value range [-2^53, 2^53]
2225
case double(Double)
2326
case bool(Bool)
24-
// not defined in datafile schema, but required for forward compatiblity (see Nikhil's doc)
27+
case array(AttrArray)
28+
case dictionary(AttrDictionary)
2529
case others
2630

2731
var description: String {
@@ -34,6 +38,10 @@ enum AttributeValue: Codable, Equatable, CustomStringConvertible {
3438
return "int(\(value))"
3539
case .bool(let value):
3640
return "bool(\(value))"
41+
case .array(let value):
42+
return "array(\(value))"
43+
case .dictionary(let value):
44+
return "dictionary(\(value))"
3745
case .others:
3846
return "others"
3947
}
@@ -63,6 +71,18 @@ enum AttributeValue: Codable, Equatable, CustomStringConvertible {
6371
self = .bool(boolValue)
6472
return
6573
}
74+
75+
if let arrValue = value as? [Any] {
76+
let attr = arrValue.compactMap { AttributeValue(value: $0) }
77+
self = .array(attr)
78+
return
79+
}
80+
81+
if let dicValue = value as? [String : Any] {
82+
let attr = dicValue.compactMapValues { AttributeValue(value: $0) }
83+
self = .dictionary(attr)
84+
return
85+
}
6686

6787
return nil
6888
}
@@ -87,7 +107,18 @@ enum AttributeValue: Codable, Equatable, CustomStringConvertible {
87107
return
88108
}
89109

90-
// accept all other types (null, {}, []) for forward compatibility support
110+
if let value = try? container.decode(AttrArray.self) {
111+
self = .array(value)
112+
return
113+
}
114+
115+
if let value = try? container.decode(AttrDictionary.self) {
116+
self = .dictionary(value)
117+
return
118+
}
119+
120+
121+
// accept all other types (null) for forward compatibility support
91122
self = .others
92123
}
93124

@@ -103,6 +134,10 @@ enum AttributeValue: Codable, Equatable, CustomStringConvertible {
103134
try container.encode(value)
104135
case .bool(let value):
105136
try container.encode(value)
137+
case .array(let value):
138+
try container.encode(value)
139+
case .dictionary(let value):
140+
try container.encode(value.mapValues { $0 })
106141
case .others:
107142
return
108143
}
@@ -135,6 +170,14 @@ extension AttributeValue {
135170
return true
136171
}
137172

173+
if case .array(let selfArr) = self, case .array(let targetArr) = targetValue {
174+
return selfArr == targetArr
175+
}
176+
177+
if case .dictionary(let selfDict) = self, case .dictionary(let targetDict) = targetValue {
178+
return selfDict == targetDict
179+
}
180+
138181
return false
139182
}
140183

@@ -227,6 +270,10 @@ extension AttributeValue {
227270
return String(value)
228271
case .bool(let value):
229272
return String(value)
273+
case .array(let value):
274+
return String(describing: value)
275+
case .dictionary(let value):
276+
return String(describing: value)
230277
case .others:
231278
return "UNKNOWN"
232279
}
@@ -240,6 +287,8 @@ extension AttributeValue {
240287
case (.double, .int): return true
241288
case (.double, .double): return true
242289
case (.bool, .bool): return true
290+
case (.array, .array): return true
291+
case (.dictionary, .dictionary): return true
243292
default: return false
244293
}
245294
}
@@ -271,6 +320,8 @@ extension AttributeValue {
271320
case (.int): return true
272321
case (.double): return true
273322
case (.bool): return true
323+
case (.array): return true
324+
case (.dictionary): return true
274325
default: return false
275326
}
276327
}

Sources/Utils/SDKVersion.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@
1717
/// Do not edit this field.
1818
/// - It is auto updated (Scripts/updated_version.sh) to reflect the current version
1919
/// - Do not put underscores in the name (Swiftlint can modify unexpectedly)
20-
let OPTIMIZELYSDKVERSION = "5.0.0"
20+
let OPTIMIZELYSDKVERSION = "5.1.0"

Tests/OptimizelyTests-Common/BatchEventBuilderTests_EventTags.swift

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ class BatchEventBuilderTests_EventTags: XCTestCase {
7676

7777
extension BatchEventBuilderTests_EventTags {
7878

79-
func testEventTagsWhenInvalidType() {
79+
func testEventTagsWhenArrayType() {
8080
let eventKey = "event_single_targeted_exp"
8181
let eventTags: [String: Any] = ["browser": "chrome",
8282
"future": [1, 2, 3]]
@@ -87,7 +87,8 @@ extension BatchEventBuilderTests_EventTags {
8787
let tags = de["tags"] as! [String: Any]
8888

8989
XCTAssertEqual(tags["browser"] as! String, "chrome")
90-
XCTAssertNil(tags["future"])
90+
XCTAssertNotNil(tags["future"])
91+
XCTAssertEqual(tags["future"] as? [Int], [1, 2, 3])
9192
}
9293

9394
func testEventTagsWhenTooBigNumbers() {
@@ -316,6 +317,55 @@ extension BatchEventBuilderTests_EventTags {
316317
XCTAssertEqual(de["value"] as! Double, 32, "value must be valid for value")
317318
}
318319

320+
321+
func testNestedTag() {
322+
let properties: [String: Any] = [
323+
"category": "shoes",
324+
"Text": "value",
325+
"nested": [
326+
"foot": "value",
327+
"mouth": "mouth_value"
328+
],
329+
"stringArray": ["a", "b", "c"],
330+
"intArray": [1, 2, 3],
331+
"doubleArray": [1.0, 2.0, 3.0],
332+
"boolAray": [false, true, false, true],
333+
]
334+
let eventKey = "event_single_targeted_exp"
335+
let eventTags: [String: Any] = ["browser": "chrome",
336+
"v1": Int8(10),
337+
"v2": Int16(20),
338+
"v3": Int32(30),
339+
"revenue": Int64(40),
340+
"value": Float(32),
341+
"$opt_event_properties": properties]
342+
343+
try! optimizely.track(eventKey: eventKey, userId: userId, attributes: nil, eventTags: eventTags)
344+
345+
let de = getDispatchEvent(dispatcher: eventDispatcher)!
346+
let tags = de["tags"] as! [String: Any]
347+
348+
XCTAssertEqual(tags["browser"] as! String, "chrome")
349+
XCTAssertEqual(tags["v1"] as! Int, 10)
350+
XCTAssertEqual(tags["v2"] as! Int, 20)
351+
XCTAssertEqual(tags["v3"] as! Int, 30)
352+
XCTAssertEqual(tags["revenue"] as! Int, 40)
353+
XCTAssertEqual(tags["value"] as! Double, 32)
354+
XCTAssertEqual(de["revenue"] as! Int, 40, "value must be valid for revenue")
355+
XCTAssertEqual(de["value"] as! Double, 32, "value must be valid for value")
356+
357+
XCTAssertEqual((tags["$opt_event_properties"] as! [String : Any])["category"] as! String, "shoes")
358+
XCTAssertEqual((tags["$opt_event_properties"] as! [String : Any])["nested"] as! [String : String], ["foot": "value", "mouth": "mouth_value"])
359+
360+
XCTAssertEqual((tags["$opt_event_properties"] as! [String : Any])["stringArray"] as! [String], ["a", "b", "c"])
361+
XCTAssertEqual((tags["$opt_event_properties"] as! [String : Any])["intArray"] as! [Int], [1, 2, 3])
362+
XCTAssertEqual((tags["$opt_event_properties"] as! [String : Any])["doubleArray"] as! [Double], [1, 2, 3])
363+
XCTAssertEqual((tags["$opt_event_properties"] as! [String : Any])["boolAray"] as! [Bool], [false, true, false, true])
364+
365+
366+
}
367+
368+
319369
func testEventTagsWithRevenueAndValue_toJSON() {
320370

321371
// valid revenue/value types

0 commit comments

Comments
 (0)