diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index a8a43bd..194819d 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -49,39 +49,39 @@ jobs: - name: Build & Run tests run: swift test - build_and_test_spm_linux: - needs: cancel_previous - runs-on: ubuntu-latest - steps: - - uses: sersoft-gmbh/swifty-linux-action@v3 - with: - release-version: "5.9.2" - github-token: ${{secrets.GITHUB_TOKEN}} - - uses: actions/checkout@v2 - - uses: webfactory/ssh-agent@v0.8.0 - with: - ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }} - - name: Build & Run tests - run: swift test --enable-test-discovery + # build_and_test_spm_linux: + # needs: cancel_previous + # runs-on: ubuntu-latest + # steps: + # - uses: sersoft-gmbh/swifty-linux-action@v3 + # with: + # release-version: "5.9.2" + # github-token: ${{secrets.GITHUB_TOKEN}} + # - uses: actions/checkout@v2 + # - uses: webfactory/ssh-agent@v0.8.0 + # with: + # ssh-private-key: ${{ secrets.SOVRAN_SSH_KEY }} + # - name: Build & Run tests + # run: swift test --enable-test-discovery - build_and_test_spm_windows: - needs: cancel_previous - runs-on: windows-latest - steps: - - uses: SwiftyLab/setup-swift@latest - with: - swift-version: "5.10" - - uses: actions/checkout@v2 - - name: Build - run: swift build - # - # Disable tests right now. There's an SPM issue where link errors generate - # a bad exit code even though the tests run/work properly. - # - # See: https://forums.swift.org/t/linker-warnings-on-windows-with-swift-argument-parser/71443/2 - # - # - name: Run tests - # run: swift test --enable-test-discovery + # build_and_test_spm_windows: + # needs: cancel_previous + # runs-on: windows-latest + # steps: + # - uses: SwiftyLab/setup-swift@latest + # with: + # swift-version: "5.10" + # - uses: actions/checkout@v2 + # - name: Build + # run: swift build + # # + # # Disable tests right now. There's an SPM issue where link errors generate + # # a bad exit code even though the tests run/work properly. + # # + # # See: https://forums.swift.org/t/linker-warnings-on-windows-with-swift-argument-parser/71443/2 + # # + # # - name: Run tests + # # run: swift test --enable-test-discovery build_and_test_ios: needs: cancel_previous diff --git a/Examples/other_plugins/InjectTraits.swift b/Examples/other_plugins/InjectTraits.swift index 8822e74..21ca3ab 100644 --- a/Examples/other_plugins/InjectTraits.swift +++ b/Examples/other_plugins/InjectTraits.swift @@ -44,7 +44,9 @@ class InjectTraits: Plugin { var workingEvent = event if var context = event?.context?.dictionaryValue { - context[keyPath: "traits"] = analytics?.traits() + if let traits = analytics?.traits() { + context[keyPath: "traits"] = analytics?.traits() + } workingEvent?.context = try? JSON(context) } diff --git a/Package.resolved b/Package.resolved index 319773e..6cf82b7 100644 --- a/Package.resolved +++ b/Package.resolved @@ -1,14 +1,5 @@ { "pins" : [ - { - "identity" : "analytics-swift-mixpanel", - "kind" : "remoteSourceControl", - "location" : "https://github.com/segment-integrations/analytics-swift-mixpanel", - "state" : { - "revision" : "bc6a9628af225e679a581cc9ac2316eaf42f23a8", - "version" : "1.1.7" - } - }, { "identity" : "jsonsafeencoding-swift", "kind" : "remoteSourceControl", @@ -18,15 +9,6 @@ "version" : "2.0.0" } }, - { - "identity" : "mixpanel-swift", - "kind" : "remoteSourceControl", - "location" : "https://github.com/mixpanel/mixpanel-swift", - "state" : { - "revision" : "48d6668ceaaefc338f94e2b084c3cf77b90182f8", - "version" : "4.3.0" - } - }, { "identity" : "sovran-swift", "kind" : "remoteSourceControl", diff --git a/Sources/Segment/Types.swift b/Sources/Segment/Types.swift index 549d0cf..a13992a 100644 --- a/Sources/Segment/Types.swift +++ b/Sources/Segment/Types.swift @@ -70,7 +70,7 @@ public struct IdentifyEvent: RawEvent { public var metrics: [JSON]? = nil public var _metadata: DestinationMetadata? = nil - public var traits: JSON? + @OmitIfNull public var traits: JSON? public init(userId: String? = nil, traits: JSON? = nil) { diff --git a/Sources/Segment/Utilities/OmitIfNull.swift b/Sources/Segment/Utilities/OmitIfNull.swift new file mode 100644 index 0000000..5be4983 --- /dev/null +++ b/Sources/Segment/Utilities/OmitIfNull.swift @@ -0,0 +1,32 @@ +// +// OmitIfNull.swift +// Segment +// +// Created by Brandon Sneed on 3/11/25. +// + +@propertyWrapper +public struct OmitIfNull: Codable { + public var wrappedValue: T? + + public init(wrappedValue: T?) { + self.wrappedValue = wrappedValue + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.singleValueContainer() + if let value = wrappedValue { + try container.encode(value) + } else { + try container.encodeNil() + } + } +} + +extension KeyedEncodingContainer { + internal mutating func encode(_ value: OmitIfNull, forKey key: Key) throws where T: Encodable { + if value.wrappedValue != nil { + try encode(value.wrappedValue, forKey: key) + } + } +} diff --git a/Tests/Segment-Tests/Analytics_Tests.swift b/Tests/Segment-Tests/Analytics_Tests.swift index 4585bac..8acacc2 100644 --- a/Tests/Segment-Tests/Analytics_Tests.swift +++ b/Tests/Segment-Tests/Analytics_Tests.swift @@ -360,6 +360,33 @@ final class Analytics_Tests: XCTestCase { let traits = identifyEvent?.traits?.dictionaryValue XCTAssertTrue(traits?["email"] as? String == "blah@blah.com") } + + func testTraitsNull() { + let analytics = Analytics(configuration: Configuration(writeKey: "test")) + let outputReader = OutputReaderPlugin() + analytics.add(plugin: outputReader) + + waitUntilStarted(analytics: analytics) + + analytics.identify(userId: "brandon", traits: nil) + + let identifyEvent: IdentifyEvent? = outputReader.lastEvent as? IdentifyEvent + + let encoder = JSONEncoder() + encoder.outputFormatting = .prettyPrinted // Makes the JSON nice and readable + + let jsonNoTraits = try! encoder.encode(identifyEvent) + let jsonNoTraitsString = String(data: jsonNoTraits, encoding: .utf8)! + + XCTAssertFalse(jsonNoTraitsString.contains("\"traits\"")) + + analytics.identify(userId: "brandon", traits: ["some": "value"]) + let identifyEventTraits: IdentifyEvent? = outputReader.lastEvent as? IdentifyEvent + let jsonWithTraits = try! encoder.encode(identifyEventTraits) + let jsonWithTraitsString = String(data: jsonWithTraits, encoding: .utf8)! + + XCTAssertTrue(jsonWithTraitsString.contains("\"traits\"")) + } func testUserIdAndTraitsPersistCorrectly() { let analytics = Analytics(configuration: Configuration(writeKey: "test"))