From 175eed30c94bf7361d8b0903a42fa92c65937718 Mon Sep 17 00:00:00 2001 From: Matthew Keeler Date: Tue, 2 Dec 2025 12:26:02 -0500 Subject: [PATCH 01/20] chore: Bump v9 -> v10 references --- .github/pull_request_template.md | 2 +- .github/workflows/ci.yml | 4 ++-- .github/workflows/release-please.yml | 2 +- README.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 7485979d..b594f3d2 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,7 +1,7 @@ **Requirements** - [ ] I have added test coverage for new or changed functionality -- [ ] I have followed the repository's [pull request submission guidelines](../blob/v9/CONTRIBUTING.md#submitting-pull-requests) +- [ ] I have followed the repository's [pull request submission guidelines](../blob/v10/CONTRIBUTING.md#submitting-pull-requests) - [ ] I have validated my changes against all supported platform versions **Related issues** diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7f7dac12..611a19ba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,11 +1,11 @@ name: Run CI on: push: - branches: [ v9, 'feat/**' ] + branches: [ v10, 'feat/**' ] paths-ignore: - '**.md' # Do not need to run CI for markdown changes. pull_request: - branches: [ v9, 'feat/**' ] + branches: [ v10, 'feat/**' ] paths-ignore: - '**.md' diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 9029a4b1..ad4aac83 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: push: branches: - - v9 + - v10 jobs: release-package: diff --git a/README.md b/README.md index 46763bfa..8cc49930 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ LaunchDarkly SDK for iOS ======================== -[![Run CI](https://github.com/launchdarkly/ios-client-sdk/actions/workflows/ci.yml/badge.svg?branch=v9)](https://github.com/launchdarkly/ios-client-sdk/actions/workflows/ci.yml) +[![Run CI](https://github.com/launchdarkly/ios-client-sdk/actions/workflows/ci.yml/badge.svg?branch=v10)](https://github.com/launchdarkly/ios-client-sdk/actions/workflows/ci.yml) [![SwiftPM compatible](https://img.shields.io/badge/SwiftPM-compatible-4BC51D.svg?style=flat)](https://swift.org/package-manager/) [![CocoaPods compatible](https://img.shields.io/cocoapods/v/LaunchDarkly.svg)](https://cocoapods.org/pods/LaunchDarkly) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) From 87ca629c32a532b2150425f888ec49f71350aa05 Mon Sep 17 00:00:00 2001 From: Todd Anderson Date: Fri, 16 Jan 2026 10:37:36 -0500 Subject: [PATCH 02/20] fixing swift lint issues --- LaunchDarkly/LaunchDarkly/LDClient.swift | 5 +++-- .../LaunchDarkly/LDClientIdentifyHook.swift | 13 +++++++------ LaunchDarkly/LaunchDarkly/Models/Hooks/Hook.swift | 11 +++++++---- .../ServiceObjects/TimeoutExecutor.swift | 6 +++--- .../LDClientIdentifyHookSpec.swift | 2 +- 5 files changed, 21 insertions(+), 16 deletions(-) diff --git a/LaunchDarkly/LaunchDarkly/LDClient.swift b/LaunchDarkly/LaunchDarkly/LDClient.swift index 411de932..68b927c4 100644 --- a/LaunchDarkly/LaunchDarkly/LDClient.swift +++ b/LaunchDarkly/LaunchDarkly/LDClient.swift @@ -332,6 +332,7 @@ public class LDClient { // Temporary helper method to allow code sharing between the sheddable and unsheddable identify methods. In the next major release, we will remove the deprecated identify method and inline // this implementation in the other one. + // swiftlint:disable:next identifier_name func _identify(context: LDContext, sheddable: Bool, useCache: IdentifyCacheUsage, completion: @escaping (_ result: IdentifyResult) -> Void) { let work: TaskHandler = { taskCompletion in let dispatch = DispatchGroup() @@ -352,7 +353,7 @@ public class LDClient { } identifyQueue.enqueue(request: identifyTask) } - + /** Sets the LDContext into the LDClient inline with the behavior detailed on `LDClient.identify(context: completion:)`. Additionally, this method will ensure the `completion` parameter will be called within the specified time interval. @@ -384,7 +385,7 @@ public class LDClient { if timeout > LDClient.longTimeoutInterval { os_log("%s LDClient.identify was called with a timeout greater than %f seconds. We recommend a timeout of less than %f seconds.", log: config.logger, type: .info, self.typeName(and: #function), LDClient.longTimeoutInterval, LDClient.longTimeoutInterval) } - + self._identifyHooked(context: context, sheddable: true, useCache: useCache, timeout: timeout, completion: completion) } diff --git a/LaunchDarkly/LaunchDarkly/LDClientIdentifyHook.swift b/LaunchDarkly/LaunchDarkly/LDClientIdentifyHook.swift index 190f3a86..8a041605 100644 --- a/LaunchDarkly/LaunchDarkly/LDClientIdentifyHook.swift +++ b/LaunchDarkly/LaunchDarkly/LDClientIdentifyHook.swift @@ -6,7 +6,7 @@ extension LDClient { let seriesData: [IdentifySeriesData] let hooksSnapshot: [Hook] } - + private func executeWithIdentifyHooks(context: LDContext, work: @escaping ((@escaping (IdentifyResult) -> Void)) -> Void) { let state = executeBeforeIdentifyHooks(context: context) work() { [weak self] result in @@ -16,12 +16,12 @@ extension LDClient { self?.executeAfterIdentifyHooks(state: state, result: result) } } - + private func executeBeforeIdentifyHooks(context: LDContext) -> IdentifyHookState? { guard !hooks.isEmpty else { return nil } - + let hooksSnapshot = self.hooks let seriesContext = IdentifySeriesContext(context: context, methodName: "identify") let seriesData = hooksSnapshot.map { hook in @@ -29,18 +29,19 @@ extension LDClient { } return IdentifyHookState(seriesContext: seriesContext, seriesData: seriesData, hooksSnapshot: hooksSnapshot) } - + private func executeAfterIdentifyHooks(state: IdentifyHookState, result: IdentifyResult) { guard !state.hooksSnapshot.isEmpty else { return } - + // Invoke hooks in reverse order and give them back the series data they gave us. zip(state.hooksSnapshot, state.seriesData).reversed().forEach { (hook, data) in _ = hook.afterIdentify(seriesContext: state.seriesContext, seriesData: data, result: result) } } - + + // swiftlint:disable:next identifier_name func _identifyHooked(context: LDContext, sheddable: Bool, useCache: IdentifyCacheUsage, timeout: TimeInterval, completion: @escaping (_ result: IdentifyResult) -> Void) { if timeout > 0 { executeWithIdentifyHooks(context: context) { hooksCompletion in diff --git a/LaunchDarkly/LaunchDarkly/Models/Hooks/Hook.swift b/LaunchDarkly/LaunchDarkly/Models/Hooks/Hook.swift index 036a22d4..3a0728db 100644 --- a/LaunchDarkly/LaunchDarkly/Models/Hooks/Hook.swift +++ b/LaunchDarkly/LaunchDarkly/Models/Hooks/Hook.swift @@ -4,13 +4,16 @@ import Foundation /// /// Hook implementations can use this to store data needed between stages. public typealias EvaluationSeriesData = [String: Any] +/// Implementation specific hook data for identify stages. +/// +/// Hook implementations can use this to store data needed between stages. public typealias IdentifySeriesData = [String: Any] /// Protocol for extending SDK functionality via hooks. public protocol Hook { /// Get metadata about the hook implementation. func metadata() -> Metadata - + /// Executed by the SDK at the start of the evaluation of a feature flag. /// /// This is not executed as part of a call to `LDClient.allFlags()`. @@ -25,7 +28,7 @@ public protocol Hook { /// `beforeEvaluation` is the first stage in this series, so this will be an empty dictionary. /// - Returns: A dictionary containing custom data that will be carried through to the next stage of the series. func beforeEvaluation(seriesContext: EvaluationSeriesContext, seriesData: EvaluationSeriesData) -> EvaluationSeriesData - + /// Executed by the SDK after the evaluation of a feature flag completes. /// /// This is not executed as part of a call to `LDClient.allFlags()`. @@ -39,7 +42,7 @@ public protocol Hook { /// - evaluationDetail: The result of the evaluation that took place before this hook was invoked. /// - Returns: A dictionary containing custom data that will be carried through to the next stage of the series (if added in the future). func afterEvaluation(seriesContext: EvaluationSeriesContext, seriesData: EvaluationSeriesData, evaluationDetail: LDEvaluationDetail) -> EvaluationSeriesData - + /// To provide custom data to the series which will be given back to your Hook at the next stage of the series, /// return a dictionary containing the custom data. You should initialize this dictionary from the `seriesData`. /// @@ -48,7 +51,7 @@ public protocol Hook { /// - seriesData: A record associated with each stage of hook invocations. Each stage is called with the data of the previous stage for a series. The input record should not be modified. /// - Returns: A dictionary containing custom data that will be carried through to the next stage of the series. func beforeIdentify(seriesContext: IdentifySeriesContext, seriesData: IdentifySeriesData) -> IdentifySeriesData - + /// Called during the execution of the identify process, after the operation completes. /// /// This is currently the last stage of the identify series in the Hook, but that may not be the case in the future. diff --git a/LaunchDarkly/LaunchDarkly/ServiceObjects/TimeoutExecutor.swift b/LaunchDarkly/LaunchDarkly/ServiceObjects/TimeoutExecutor.swift index 8b81f908..e75ee200 100644 --- a/LaunchDarkly/LaunchDarkly/ServiceObjects/TimeoutExecutor.swift +++ b/LaunchDarkly/LaunchDarkly/ServiceObjects/TimeoutExecutor.swift @@ -39,7 +39,7 @@ final class TimeoutExecutor { } return } - + let lockQueue = DispatchQueue(label: "launchdarkly.timeout.executor.lock") var finished = false @@ -52,7 +52,7 @@ final class TimeoutExecutor { shouldCall = true } } - + if shouldCall { queue.async { completion(value) } } @@ -67,7 +67,7 @@ final class TimeoutExecutor { shouldCall = true } } - + if shouldCall { completion(timeoutValue()) } diff --git a/LaunchDarkly/LaunchDarklyTests/LDClientIdentifyHookSpec.swift b/LaunchDarkly/LaunchDarklyTests/LDClientIdentifyHookSpec.swift index b5f93c9a..73c6d365 100644 --- a/LaunchDarkly/LaunchDarklyTests/LDClientIdentifyHookSpec.swift +++ b/LaunchDarkly/LaunchDarklyTests/LDClientIdentifyHookSpec.swift @@ -20,7 +20,7 @@ final class LDClientIdentifyHookSpec: XCTestCase { testContext.subject.identify(context: LDContext.stub()) { _ in } expect(count).toEventually(equal(3)) } - + func testRegistrationWithTimeout() { var count = 0 let hook = MockHook(before: { _, data in count += 1; return data }, after: { _, data, _ in count += 2; return data }) From 259ca9d6f5b0de4d459eb230ffa3ec09e962c87b Mon Sep 17 00:00:00 2001 From: Todd Anderson Date: Fri, 16 Jan 2026 10:54:32 -0500 Subject: [PATCH 03/20] bumping macos runner version --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 611a19ba..0b1d9f59 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,11 +19,11 @@ jobs: include: - xcode-version: 15.0.1 ios-sim: 'platform=iOS Simulator,name=iPhone 15,OS=17.2' - os: macos-13 + os: macos-14 run-contract-tests: true - xcode-version: 14.3.1 ios-sim: 'platform=iOS Simulator,name=iPhone 14,OS=16.4' - os: macos-13 + os: macos-14 run-contract-tests: false steps: From e9f01fa929ea42e4ebbfc15830fb2e8419ff4504 Mon Sep 17 00:00:00 2001 From: Todd Anderson Date: Fri, 16 Jan 2026 10:56:29 -0500 Subject: [PATCH 04/20] bumping xcode versions --- .github/workflows/ci.yml | 4 ++-- .github/workflows/manual-publish-docs.yml | 2 +- .github/workflows/manual-publish.yml | 2 +- .github/workflows/release-please.yml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0b1d9f59..40b1821e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,11 +17,11 @@ jobs: fail-fast: false matrix: include: - - xcode-version: 15.0.1 + - xcode-version: 16.2.0 ios-sim: 'platform=iOS Simulator,name=iPhone 15,OS=17.2' os: macos-14 run-contract-tests: true - - xcode-version: 14.3.1 + - xcode-version: 15.4.0 ios-sim: 'platform=iOS Simulator,name=iPhone 14,OS=16.4' os: macos-14 run-contract-tests: false diff --git a/.github/workflows/manual-publish-docs.yml b/.github/workflows/manual-publish-docs.yml index 125a4710..6d134a02 100644 --- a/.github/workflows/manual-publish-docs.yml +++ b/.github/workflows/manual-publish-docs.yml @@ -16,7 +16,7 @@ jobs: - name: Build and Test uses: ./.github/actions/ci with: - xcode-version: 15.0.1 + xcode-version: 16.2.0 ios-sim: 'platform=iOS Simulator,name=iPhone 15,OS=17.2' run-contract-tests: true token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/manual-publish.yml b/.github/workflows/manual-publish.yml index 533bf330..febf0519 100644 --- a/.github/workflows/manual-publish.yml +++ b/.github/workflows/manual-publish.yml @@ -27,7 +27,7 @@ jobs: - uses: ./.github/actions/ci with: - xcode-version: 15.0.1 + xcode-version: 16.2.0 ios-sim: 'platform=iOS Simulator,name=iPhone 15,OS=17.2' run-contract-tests: true token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index d4e5ee55..057a6c90 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -46,7 +46,7 @@ jobs: - uses: ./.github/actions/ci if: ${{ steps.release.outputs.releases_created == 'true' }} with: - xcode-version: 15.0.1 + xcode-version: 16.2.0 ios-sim: 'platform=iOS Simulator,name=iPhone 15,OS=17.2' run-contract-tests: true token: ${{ secrets.GITHUB_TOKEN }} From 28a06eae03bdc2e3e5330a0d59c64e6cf13c6463 Mon Sep 17 00:00:00 2001 From: Todd Anderson Date: Fri, 16 Jan 2026 11:05:27 -0500 Subject: [PATCH 05/20] more tweaks --- .github/actions/ci/action.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/actions/ci/action.yml b/.github/actions/ci/action.yml index b30547be..b2d6c5b7 100644 --- a/.github/actions/ci/action.yml +++ b/.github/actions/ci/action.yml @@ -29,6 +29,11 @@ runs: run: | brew install mint + - name: Install swiftlint + shell: bash + run: | + brew install swiftlint + - name: Install cocoapods shell: bash run: gem install cocoapods @@ -37,7 +42,7 @@ runs: shell: bash run: pod lib lint LaunchDarkly.podspec --allow-warnings - - name: Run swiftlint + - name: Run swiftlint on ContractTests shell: bash run: | cd ./ContractTests From 931d49c798924a7863bd0ef9d2dc5bd93e675b4b Mon Sep 17 00:00:00 2001 From: Todd Anderson Date: Fri, 16 Jan 2026 12:09:06 -0500 Subject: [PATCH 06/20] but wait, there's more tweaks --- .github/actions/ci/action.yml | 5 ++++ LaunchDarkly.xcodeproj/project.pbxproj | 32 ++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/.github/actions/ci/action.yml b/.github/actions/ci/action.yml index b2d6c5b7..2cd7b7ad 100644 --- a/.github/actions/ci/action.yml +++ b/.github/actions/ci/action.yml @@ -38,6 +38,11 @@ runs: shell: bash run: gem install cocoapods + - name: Install xcpretty + shell: bash + run: | + gem install xcpretty + - name: Lint the podspec shell: bash run: pod lib lint LaunchDarkly.podspec --allow-warnings diff --git a/LaunchDarkly.xcodeproj/project.pbxproj b/LaunchDarkly.xcodeproj/project.pbxproj index e4ced8f8..103cc3f4 100644 --- a/LaunchDarkly.xcodeproj/project.pbxproj +++ b/LaunchDarkly.xcodeproj/project.pbxproj @@ -303,7 +303,16 @@ A3BA7CF42BD05A280000DB28 /* EvaluationSeriesContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BA7CF22BD05A280000DB28 /* EvaluationSeriesContext.swift */; }; A3BA7CF52BD05A280000DB28 /* EvaluationSeriesContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BA7CF22BD05A280000DB28 /* EvaluationSeriesContext.swift */; }; A3BA7CF62BD05A280000DB28 /* EvaluationSeriesContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BA7CF22BD05A280000DB28 /* EvaluationSeriesContext.swift */; }; - A3BA7D022BD192240000DB28 /* LDClientHookSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BA7D012BD192240000DB28 /* LDClientHookSpec.swift */; }; + A3BA7CF72BD05A290000DB28 /* IdentifySeriesContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BA7CF82BD05A290000DB28 /* IdentifySeriesContext.swift */; }; + A3BA7CF92BD05A290000DB28 /* IdentifySeriesContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BA7CF82BD05A290000DB28 /* IdentifySeriesContext.swift */; }; + A3BA7CFA2BD05A290000DB28 /* IdentifySeriesContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BA7CF82BD05A290000DB28 /* IdentifySeriesContext.swift */; }; + A3BA7CFB2BD05A290000DB28 /* IdentifySeriesContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BA7CF82BD05A290000DB28 /* IdentifySeriesContext.swift */; }; + A3BA7CFC2BD05A2A0000DB28 /* LDClientIdentifyHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BA7CFD2BD05A2A0000DB28 /* LDClientIdentifyHook.swift */; }; + A3BA7CFE2BD05A2A0000DB28 /* LDClientIdentifyHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BA7CFD2BD05A2A0000DB28 /* LDClientIdentifyHook.swift */; }; + A3BA7CFF2BD05A2A0000DB28 /* LDClientIdentifyHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BA7CFD2BD05A2A0000DB28 /* LDClientIdentifyHook.swift */; }; + A3BA7D002BD05A2A0000DB28 /* LDClientIdentifyHook.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BA7CFD2BD05A2A0000DB28 /* LDClientIdentifyHook.swift */; }; + A3BA7D072BD192250000DB28 /* LDClientEvaluationHookSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BA7D052BD192250000DB28 /* LDClientEvaluationHookSpec.swift */; }; + A3BA7D082BD192250000DB28 /* LDClientIdentifyHookSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BA7D062BD192250000DB28 /* LDClientIdentifyHookSpec.swift */; }; A3BA7D042BD2BD620000DB28 /* TestContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3BA7D032BD2BD620000DB28 /* TestContext.swift */; }; A3C6F7622B7FA803005B3B61 /* SheddingQueueSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3C6F7612B7FA803005B3B61 /* SheddingQueueSpec.swift */; }; A3C6F7642B84EF0C005B3B61 /* IdentifyTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = A3C6F7632B84EF0C005B3B61 /* IdentifyTypes.swift */; }; @@ -537,7 +546,10 @@ A3BA7CE82BD056920000DB28 /* Hook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Hook.swift; sourceTree = ""; }; A3BA7CED2BD059180000DB28 /* Metadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Metadata.swift; sourceTree = ""; }; A3BA7CF22BD05A280000DB28 /* EvaluationSeriesContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EvaluationSeriesContext.swift; sourceTree = ""; }; - A3BA7D012BD192240000DB28 /* LDClientHookSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LDClientHookSpec.swift; sourceTree = ""; }; + A3BA7CF82BD05A290000DB28 /* IdentifySeriesContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentifySeriesContext.swift; sourceTree = ""; }; + A3BA7CFD2BD05A2A0000DB28 /* LDClientIdentifyHook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LDClientIdentifyHook.swift; sourceTree = ""; }; + A3BA7D052BD192250000DB28 /* LDClientEvaluationHookSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LDClientEvaluationHookSpec.swift; sourceTree = ""; }; + A3BA7D062BD192250000DB28 /* LDClientIdentifyHookSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LDClientIdentifyHookSpec.swift; sourceTree = ""; }; A3BA7D032BD2BD620000DB28 /* TestContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestContext.swift; sourceTree = ""; }; A3C6F7612B7FA803005B3B61 /* SheddingQueueSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SheddingQueueSpec.swift; sourceTree = ""; }; A3C6F7632B84EF0C005B3B61 /* IdentifyTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IdentifyTypes.swift; sourceTree = ""; }; @@ -723,6 +735,7 @@ A380B0982B60178D00AB64A6 /* PrivacyInfo.xcprivacy */, 83B6C4B51F4DE7630055351C /* LDCommon.swift */, 8354EFDC1F26380700C05156 /* LDClient.swift */, + A3BA7CFD2BD05A2A0000DB28 /* LDClientIdentifyHook.swift */, B495A8A12787762C0051977C /* LDClientVariation.swift */, 29FE1297280413D4008CC918 /* Util.swift */, 8354EFE61F263E4200C05156 /* Models */, @@ -741,7 +754,8 @@ isa = PBXGroup; children = ( 3D2406242E0D90EA00F91253 /* LDClientPluginsSpec.swift */, - A3BA7D012BD192240000DB28 /* LDClientHookSpec.swift */, + A3BA7D052BD192250000DB28 /* LDClientEvaluationHookSpec.swift */, + A3BA7D062BD192250000DB28 /* LDClientIdentifyHookSpec.swift */, 838F96731FB9F024009CFC45 /* LDClientSpec.swift */, 3D9A12572A73236800698B8D /* UtilSpec.swift */, 83EF67911F9945CE00403126 /* Models */, @@ -972,6 +986,7 @@ A3BA7CE82BD056920000DB28 /* Hook.swift */, A3BA7CED2BD059180000DB28 /* Metadata.swift */, A3BA7CF22BD05A280000DB28 /* EvaluationSeriesContext.swift */, + A3BA7CF82BD05A290000DB28 /* IdentifySeriesContext.swift */, ); path = Hooks; sourceTree = ""; @@ -1358,6 +1373,7 @@ 3D2406172E0D90E000F91253 /* SdkMetadata.swift in Sources */, A358D6DA2A4DE6A500270C60 /* ApplicationInfoEnvironmentReporter.swift in Sources */, 831188452113ADC500D77CB5 /* LDClient.swift in Sources */, + A3BA7CFC2BD05A2A0000DB28 /* LDClientIdentifyHook.swift in Sources */, A3BA7CF12BD059180000DB28 /* Metadata.swift in Sources */, A310881E2837DC0400184942 /* Kind.swift in Sources */, A310881A2837DC0400184942 /* Reference.swift in Sources */, @@ -1373,6 +1389,7 @@ C43C37E8238DF22D003C1624 /* LDEvaluationDetail.swift in Sources */, 8311884C2113ADDE00D77CB5 /* FlagChangeObserver.swift in Sources */, A3BA7CF62BD05A280000DB28 /* EvaluationSeriesContext.swift in Sources */, + A3BA7CFB2BD05A290000DB28 /* IdentifySeriesContext.swift in Sources */, A3470C3A2B7C1ACE00951CEE /* LDValueDecoder.swift in Sources */, C443A41223186A4F00145710 /* ConnectionModeChangeObserver.swift in Sources */, 831188592113AE1200D77CB5 /* FlagStore.swift in Sources */, @@ -1428,6 +1445,7 @@ 831EF34420655E730001C643 /* LDConfig.swift in Sources */, A31088212837DC0400184942 /* LDContext.swift in Sources */, 831EF34520655E730001C643 /* LDClient.swift in Sources */, + A3BA7CFE2BD05A2A0000DB28 /* LDClientIdentifyHook.swift in Sources */, A3BA7CF02BD059180000DB28 /* Metadata.swift in Sources */, 830DB3B02239B54900D65D25 /* URLResponse.swift in Sources */, B4C9D4352489C8FD004A9B03 /* DiagnosticCache.swift in Sources */, @@ -1460,6 +1478,7 @@ A358D6F42A4DEB4C00270C60 /* EnvironmentReporterBuilder.swift in Sources */, B4C9D4302489B5FF004A9B03 /* DiagnosticEvent.swift in Sources */, A3BA7CF52BD05A280000DB28 /* EvaluationSeriesContext.swift in Sources */, + A3BA7CFA2BD05A290000DB28 /* IdentifySeriesContext.swift in Sources */, 831EF35620655E730001C643 /* FlagChangeNotifier.swift in Sources */, A358D6D92A4DE6A500270C60 /* ApplicationInfoEnvironmentReporter.swift in Sources */, 831EF35720655E730001C643 /* EventReporter.swift in Sources */, @@ -1528,6 +1547,7 @@ 8358F25E1F474E5900ECE1AF /* LDChangedFlag.swift in Sources */, 83D559741FD87CC9002D10C8 /* KeyedValueCache.swift in Sources */, A3BA7CF32BD05A280000DB28 /* EvaluationSeriesContext.swift in Sources */, + A3BA7CF92BD05A290000DB28 /* IdentifySeriesContext.swift in Sources */, A3470C372B7C1ACE00951CEE /* LDValueDecoder.swift in Sources */, C43C37E1236BA050003C1624 /* LDEvaluationDetail.swift in Sources */, 831AAE2C20A9E4F600B46DBA /* Throttler.swift in Sources */, @@ -1545,6 +1565,7 @@ A358D6DD2A4DE7D600270C60 /* IOSEnvironmentReporter.swift in Sources */, 83B9A082204F6022000C3F17 /* FlagsUnchangedObserver.swift in Sources */, 8354EFE01F26380700C05156 /* LDClient.swift in Sources */, + A3BA7CFF2BD05A2A0000DB28 /* LDClientIdentifyHook.swift in Sources */, 831425B1206B030100F2EF36 /* EnvironmentReporter.swift in Sources */, C408884723033B3600420721 /* ConnectionInformationStore.swift in Sources */, 83B6C4B61F4DE7630055351C /* LDCommon.swift in Sources */, @@ -1621,7 +1642,8 @@ 50EE85C72EA0749C007CC662 /* TimeoutExecutorSpec.swift in Sources */, 837406D421F760640087B22B /* LDTimerSpec.swift in Sources */, 832307A61F7D8D720029815A /* URLRequestSpec.swift in Sources */, - A3BA7D022BD192240000DB28 /* LDClientHookSpec.swift in Sources */, + A3BA7D072BD192250000DB28 /* LDClientEvaluationHookSpec.swift in Sources */, + A3BA7D082BD192250000DB28 /* LDClientIdentifyHookSpec.swift in Sources */, 832307A81F7DA61B0029815A /* LDEventSourceMock.swift in Sources */, 838F967A1FBA551A009CFC45 /* ClientServiceMockFactory.swift in Sources */, A31088292837DCA900184942 /* KindSpec.swift in Sources */, @@ -1636,6 +1658,7 @@ 83D9EC762062DEAB004D7FA6 /* LDConfig.swift in Sources */, 83EBCBB420DABE1B003A7142 /* FlagRequestTracker.swift in Sources */, 83D9EC772062DEAB004D7FA6 /* LDClient.swift in Sources */, + A3BA7D002BD05A2A0000DB28 /* LDClientIdentifyHook.swift in Sources */, B4C9D4342489C8FD004A9B03 /* DiagnosticCache.swift in Sources */, 83D9EC7C2062DEAB004D7FA6 /* FeatureFlag.swift in Sources */, A36EDFCE2853C50B00D91B05 /* ObjcLDContext.swift in Sources */, @@ -1661,6 +1684,7 @@ A358D6F02A4DE9EB00270C60 /* WatchOSEnvironmentReporter.swift in Sources */, 831AAE2D20A9E4F600B46DBA /* Throttler.swift in Sources */, A3BA7CF42BD05A280000DB28 /* EvaluationSeriesContext.swift in Sources */, + A3BA7CF72BD05A290000DB28 /* IdentifySeriesContext.swift in Sources */, A3470C382B7C1ACE00951CEE /* LDValueDecoder.swift in Sources */, C43C37E6238DF22B003C1624 /* LDEvaluationDetail.swift in Sources */, 83D9EC872062DEAB004D7FA6 /* FlagSynchronizer.swift in Sources */, From 91f0958c39839bc5ead55407d2b7aedb636f2d89 Mon Sep 17 00:00:00 2001 From: Todd Anderson Date: Fri, 16 Jan 2026 13:21:28 -0500 Subject: [PATCH 07/20] loosening simulator constraint --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 40b1821e..f49fb782 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,11 +18,11 @@ jobs: matrix: include: - xcode-version: 16.2.0 - ios-sim: 'platform=iOS Simulator,name=iPhone 15,OS=17.2' + ios-sim: 'platform=iOS Simulator,name=iPhone 16' os: macos-14 run-contract-tests: true - xcode-version: 15.4.0 - ios-sim: 'platform=iOS Simulator,name=iPhone 14,OS=16.4' + ios-sim: 'platform=iOS Simulator,name=iPhone 15' os: macos-14 run-contract-tests: false From 5b36ad0cabef9b10cae803a999ee7c547ec4e9b6 Mon Sep 17 00:00:00 2001 From: Todd Anderson Date: Fri, 16 Jan 2026 15:21:03 -0500 Subject: [PATCH 08/20] upping to use macos-15 and xcode 16.4.0 in ci --- .github/workflows/ci.yml | 4 ++-- .github/workflows/manual-publish-docs.yml | 6 +++--- .github/workflows/manual-publish.yml | 6 +++--- .github/workflows/release-please.yml | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f49fb782..51af6e9d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,9 +17,9 @@ jobs: fail-fast: false matrix: include: - - xcode-version: 16.2.0 + - xcode-version: 16.4.0 ios-sim: 'platform=iOS Simulator,name=iPhone 16' - os: macos-14 + os: macos-15 run-contract-tests: true - xcode-version: 15.4.0 ios-sim: 'platform=iOS Simulator,name=iPhone 15' diff --git a/.github/workflows/manual-publish-docs.yml b/.github/workflows/manual-publish-docs.yml index 6d134a02..f1002c55 100644 --- a/.github/workflows/manual-publish-docs.yml +++ b/.github/workflows/manual-publish-docs.yml @@ -4,7 +4,7 @@ on: name: Publish Documentation jobs: build-publish: - runs-on: macos-14 + runs-on: macos-15 permissions: id-token: write # Needed if using OIDC to get release secrets. @@ -16,8 +16,8 @@ jobs: - name: Build and Test uses: ./.github/actions/ci with: - xcode-version: 16.2.0 - ios-sim: 'platform=iOS Simulator,name=iPhone 15,OS=17.2' + xcode-version: 16.4.0 + ios-sim: 'platform=iOS Simulator,name=iPhone 15' run-contract-tests: true token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/manual-publish.yml b/.github/workflows/manual-publish.yml index febf0519..bc65be5d 100644 --- a/.github/workflows/manual-publish.yml +++ b/.github/workflows/manual-publish.yml @@ -9,7 +9,7 @@ on: jobs: build-publish: - runs-on: macos-14 + runs-on: macos-15 # Needed to get tokens during publishing. permissions: @@ -27,8 +27,8 @@ jobs: - uses: ./.github/actions/ci with: - xcode-version: 16.2.0 - ios-sim: 'platform=iOS Simulator,name=iPhone 15,OS=17.2' + xcode-version: 16.4.0 + ios-sim: 'platform=iOS Simulator,name=iPhone 15' run-contract-tests: true token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 057a6c90..ed85c412 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -8,7 +8,7 @@ on: jobs: release-package: - runs-on: macos-14 + runs-on: macos-15 permissions: id-token: write # Needed if using OIDC to get release secrets. @@ -46,8 +46,8 @@ jobs: - uses: ./.github/actions/ci if: ${{ steps.release.outputs.releases_created == 'true' }} with: - xcode-version: 16.2.0 - ios-sim: 'platform=iOS Simulator,name=iPhone 15,OS=17.2' + xcode-version: 16.4.0 + ios-sim: 'platform=iOS Simulator,name=iPhone 15' run-contract-tests: true token: ${{ secrets.GITHUB_TOKEN }} From ac90fbe392ed2e199ed1b706596502de7564784b Mon Sep 17 00:00:00 2001 From: Todd Anderson Date: Fri, 16 Jan 2026 15:36:46 -0500 Subject: [PATCH 09/20] enhancing build script to log swift lint output --- LaunchDarkly.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/LaunchDarkly.xcodeproj/project.pbxproj b/LaunchDarkly.xcodeproj/project.pbxproj index 103cc3f4..c5b8f82b 100644 --- a/LaunchDarkly.xcodeproj/project.pbxproj +++ b/LaunchDarkly.xcodeproj/project.pbxproj @@ -1288,7 +1288,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\nif which mint >/dev/null; then\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\"\nfi\n"; + shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\necho \"[SwiftLint] Starting SwiftLint check...\"\necho \"[SwiftLint] PATH: $PATH\"\necho \"[SwiftLint] Working directory: $(pwd)\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\"\n if [ $SWIFTLINT_EXIT_CODE -ne 0 ]; then\n echo \"[SwiftLint] ERROR: SwiftLint found violations (exit code: $SWIFTLINT_EXIT_CODE)\"\n echo \"[SwiftLint] Build will fail due to SwiftLint errors.\"\n else\n echo \"[SwiftLint] SUCCESS: SwiftLint passed with no violations.\"\n fi\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\"\nfi\n"; }; 830C2AC2207416A5001D645D /* Run Script */ = { isa = PBXShellScriptBuildPhase; @@ -1303,7 +1303,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\nif which mint >/dev/null; then\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\"\nfi\n"; + shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\necho \"[SwiftLint] Starting SwiftLint check...\"\necho \"[SwiftLint] PATH: $PATH\"\necho \"[SwiftLint] Working directory: $(pwd)\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\"\n if [ $SWIFTLINT_EXIT_CODE -ne 0 ]; then\n echo \"[SwiftLint] ERROR: SwiftLint found violations (exit code: $SWIFTLINT_EXIT_CODE)\"\n echo \"[SwiftLint] Build will fail due to SwiftLint errors.\"\n else\n echo \"[SwiftLint] SUCCESS: SwiftLint passed with no violations.\"\n fi\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\"\nfi\n"; }; 833FD9F821C01333001F80EB /* ShellScript */ = { isa = PBXShellScriptBuildPhase; @@ -1321,7 +1321,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\nif which mint >/dev/null; then\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\"\nfi\n"; + shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\necho \"[SwiftLint] Starting SwiftLint check...\"\necho \"[SwiftLint] PATH: $PATH\"\necho \"[SwiftLint] Working directory: $(pwd)\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\"\n if [ $SWIFTLINT_EXIT_CODE -ne 0 ]; then\n echo \"[SwiftLint] ERROR: SwiftLint found violations (exit code: $SWIFTLINT_EXIT_CODE)\"\n echo \"[SwiftLint] Build will fail due to SwiftLint errors.\"\n else\n echo \"[SwiftLint] SUCCESS: SwiftLint passed with no violations.\"\n fi\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\"\nfi\n"; }; 83411A561FABCA2200E5CF39 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; @@ -1350,7 +1350,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\nif which mint >/dev/null; then\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\"\nfi\n"; + shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\necho \"[SwiftLint] Starting SwiftLint check...\"\necho \"[SwiftLint] PATH: $PATH\"\necho \"[SwiftLint] Working directory: $(pwd)\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\"\n if [ $SWIFTLINT_EXIT_CODE -ne 0 ]; then\n echo \"[SwiftLint] ERROR: SwiftLint found violations (exit code: $SWIFTLINT_EXIT_CODE)\"\n echo \"[SwiftLint] Build will fail due to SwiftLint errors.\"\n else\n echo \"[SwiftLint] SUCCESS: SwiftLint passed with no violations.\"\n fi\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\"\nfi\n"; }; /* End PBXShellScriptBuildPhase section */ From 029439460397fb718f97060c872c4a4e4016165e Mon Sep 17 00:00:00 2001 From: Todd Anderson Date: Fri, 16 Jan 2026 15:49:00 -0500 Subject: [PATCH 10/20] more script tweaks --- LaunchDarkly.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/LaunchDarkly.xcodeproj/project.pbxproj b/LaunchDarkly.xcodeproj/project.pbxproj index c5b8f82b..5630c012 100644 --- a/LaunchDarkly.xcodeproj/project.pbxproj +++ b/LaunchDarkly.xcodeproj/project.pbxproj @@ -1288,7 +1288,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\necho \"[SwiftLint] Starting SwiftLint check...\"\necho \"[SwiftLint] PATH: $PATH\"\necho \"[SwiftLint] Working directory: $(pwd)\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\"\n if [ $SWIFTLINT_EXIT_CODE -ne 0 ]; then\n echo \"[SwiftLint] ERROR: SwiftLint found violations (exit code: $SWIFTLINT_EXIT_CODE)\"\n echo \"[SwiftLint] Build will fail due to SwiftLint errors.\"\n else\n echo \"[SwiftLint] SUCCESS: SwiftLint passed with no violations.\"\n fi\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\"\nfi\n"; + shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\n# Redirect all output to stderr so it's visible even with xcpretty\nexec >&2\n\necho \"[SwiftLint] Starting SwiftLint check...\"\necho \"[SwiftLint] PATH: $PATH\"\necho \"[SwiftLint] Working directory: $(pwd)\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\"\n if [ $SWIFTLINT_EXIT_CODE -ne 0 ]; then\n echo \"[SwiftLint] ERROR: SwiftLint found violations (exit code: $SWIFTLINT_EXIT_CODE)\"\n echo \"[SwiftLint] Build will fail due to SwiftLint errors.\"\n else\n echo \"[SwiftLint] SUCCESS: SwiftLint passed with no violations.\"\n fi\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\"\nfi\n"; }; 830C2AC2207416A5001D645D /* Run Script */ = { isa = PBXShellScriptBuildPhase; @@ -1303,7 +1303,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\necho \"[SwiftLint] Starting SwiftLint check...\"\necho \"[SwiftLint] PATH: $PATH\"\necho \"[SwiftLint] Working directory: $(pwd)\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\"\n if [ $SWIFTLINT_EXIT_CODE -ne 0 ]; then\n echo \"[SwiftLint] ERROR: SwiftLint found violations (exit code: $SWIFTLINT_EXIT_CODE)\"\n echo \"[SwiftLint] Build will fail due to SwiftLint errors.\"\n else\n echo \"[SwiftLint] SUCCESS: SwiftLint passed with no violations.\"\n fi\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\"\nfi\n"; + shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\n# Redirect all output to stderr so it's visible even with xcpretty\nexec >&2\n\necho \"[SwiftLint] Starting SwiftLint check...\"\necho \"[SwiftLint] PATH: $PATH\"\necho \"[SwiftLint] Working directory: $(pwd)\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\"\n if [ $SWIFTLINT_EXIT_CODE -ne 0 ]; then\n echo \"[SwiftLint] ERROR: SwiftLint found violations (exit code: $SWIFTLINT_EXIT_CODE)\"\n echo \"[SwiftLint] Build will fail due to SwiftLint errors.\"\n else\n echo \"[SwiftLint] SUCCESS: SwiftLint passed with no violations.\"\n fi\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\"\nfi\n"; }; 833FD9F821C01333001F80EB /* ShellScript */ = { isa = PBXShellScriptBuildPhase; @@ -1321,7 +1321,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\necho \"[SwiftLint] Starting SwiftLint check...\"\necho \"[SwiftLint] PATH: $PATH\"\necho \"[SwiftLint] Working directory: $(pwd)\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\"\n if [ $SWIFTLINT_EXIT_CODE -ne 0 ]; then\n echo \"[SwiftLint] ERROR: SwiftLint found violations (exit code: $SWIFTLINT_EXIT_CODE)\"\n echo \"[SwiftLint] Build will fail due to SwiftLint errors.\"\n else\n echo \"[SwiftLint] SUCCESS: SwiftLint passed with no violations.\"\n fi\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\"\nfi\n"; + shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\n# Redirect all output to stderr so it's visible even with xcpretty\nexec >&2\n\necho \"[SwiftLint] Starting SwiftLint check...\"\necho \"[SwiftLint] PATH: $PATH\"\necho \"[SwiftLint] Working directory: $(pwd)\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\"\n if [ $SWIFTLINT_EXIT_CODE -ne 0 ]; then\n echo \"[SwiftLint] ERROR: SwiftLint found violations (exit code: $SWIFTLINT_EXIT_CODE)\"\n echo \"[SwiftLint] Build will fail due to SwiftLint errors.\"\n else\n echo \"[SwiftLint] SUCCESS: SwiftLint passed with no violations.\"\n fi\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\"\nfi\n"; }; 83411A561FABCA2200E5CF39 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; @@ -1350,7 +1350,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\necho \"[SwiftLint] Starting SwiftLint check...\"\necho \"[SwiftLint] PATH: $PATH\"\necho \"[SwiftLint] Working directory: $(pwd)\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\"\n if [ $SWIFTLINT_EXIT_CODE -ne 0 ]; then\n echo \"[SwiftLint] ERROR: SwiftLint found violations (exit code: $SWIFTLINT_EXIT_CODE)\"\n echo \"[SwiftLint] Build will fail due to SwiftLint errors.\"\n else\n echo \"[SwiftLint] SUCCESS: SwiftLint passed with no violations.\"\n fi\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\"\nfi\n"; + shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\n# Redirect all output to stderr so it's visible even with xcpretty\nexec >&2\n\necho \"[SwiftLint] Starting SwiftLint check...\"\necho \"[SwiftLint] PATH: $PATH\"\necho \"[SwiftLint] Working directory: $(pwd)\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\"\n if [ $SWIFTLINT_EXIT_CODE -ne 0 ]; then\n echo \"[SwiftLint] ERROR: SwiftLint found violations (exit code: $SWIFTLINT_EXIT_CODE)\"\n echo \"[SwiftLint] Build will fail due to SwiftLint errors.\"\n else\n echo \"[SwiftLint] SUCCESS: SwiftLint passed with no violations.\"\n fi\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\"\nfi\n"; }; /* End PBXShellScriptBuildPhase section */ From 8e22ab52b96f6af84c0dfd92f00a5f05f14ffbc1 Mon Sep 17 00:00:00 2001 From: Todd Anderson Date: Fri, 16 Jan 2026 16:36:09 -0500 Subject: [PATCH 11/20] swiftlint output to temp file --- .github/actions/ci/action.yml | 12 ++++++++++++ LaunchDarkly.xcodeproj/project.pbxproj | 8 ++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/.github/actions/ci/action.yml b/.github/actions/ci/action.yml index 2cd7b7ad..f197f240 100644 --- a/.github/actions/ci/action.yml +++ b/.github/actions/ci/action.yml @@ -57,6 +57,18 @@ runs: shell: bash run: xcodebuild build -scheme 'LaunchDarkly_macOS' -sdk macosx -destination 'platform=macOS' | xcpretty + - name: Display SwiftLint output (if build failed) + shell: bash + if: failure() + run: | + if [ -f swiftlint_build_output.log ]; then + echo "=== SwiftLint Build Script Output ===" + cat swiftlint_build_output.log + echo "=== End SwiftLint Output ===" + else + echo "No SwiftLint log file found" + fi + - name: Build Tests for iOS device shell: bash run: xcodebuild build-for-testing -scheme 'LaunchDarkly_iOS' -sdk iphoneos CODE_SIGN_IDENTITY= | xcpretty diff --git a/LaunchDarkly.xcodeproj/project.pbxproj b/LaunchDarkly.xcodeproj/project.pbxproj index 5630c012..16ba6d8a 100644 --- a/LaunchDarkly.xcodeproj/project.pbxproj +++ b/LaunchDarkly.xcodeproj/project.pbxproj @@ -1288,7 +1288,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\n# Redirect all output to stderr so it's visible even with xcpretty\nexec >&2\n\necho \"[SwiftLint] Starting SwiftLint check...\"\necho \"[SwiftLint] PATH: $PATH\"\necho \"[SwiftLint] Working directory: $(pwd)\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\"\n if [ $SWIFTLINT_EXIT_CODE -ne 0 ]; then\n echo \"[SwiftLint] ERROR: SwiftLint found violations (exit code: $SWIFTLINT_EXIT_CODE)\"\n echo \"[SwiftLint] Build will fail due to SwiftLint errors.\"\n else\n echo \"[SwiftLint] SUCCESS: SwiftLint passed with no violations.\"\n fi\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\"\nfi\n"; + shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\n# Write to a file in the workspace that persists after build\nLOG_FILE=\"${SRCROOT}/swiftlint_build_output.log\"\n\necho \"[SwiftLint] Starting SwiftLint check...\" >> \"$LOG_FILE\"\necho \"[SwiftLint] PATH: $PATH\" >> \"$LOG_FILE\"\necho \"[SwiftLint] Working directory: $(pwd)\" >> \"$LOG_FILE\"\necho \"[SwiftLint] SRCROOT: ${SRCROOT}\" >> \"$LOG_FILE\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\" >> \"$LOG_FILE\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\" >> \"$LOG_FILE\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint >> \"$LOG_FILE\" 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\" >> \"$LOG_FILE\"\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\" >> \"$LOG_FILE\"\nfi\n"; }; 830C2AC2207416A5001D645D /* Run Script */ = { isa = PBXShellScriptBuildPhase; @@ -1303,7 +1303,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\n# Redirect all output to stderr so it's visible even with xcpretty\nexec >&2\n\necho \"[SwiftLint] Starting SwiftLint check...\"\necho \"[SwiftLint] PATH: $PATH\"\necho \"[SwiftLint] Working directory: $(pwd)\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\"\n if [ $SWIFTLINT_EXIT_CODE -ne 0 ]; then\n echo \"[SwiftLint] ERROR: SwiftLint found violations (exit code: $SWIFTLINT_EXIT_CODE)\"\n echo \"[SwiftLint] Build will fail due to SwiftLint errors.\"\n else\n echo \"[SwiftLint] SUCCESS: SwiftLint passed with no violations.\"\n fi\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\"\nfi\n"; + shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\n# Write to a file in the workspace that persists after build\nLOG_FILE=\"${SRCROOT}/swiftlint_build_output.log\"\n\necho \"[SwiftLint] Starting SwiftLint check...\" >> \"$LOG_FILE\"\necho \"[SwiftLint] PATH: $PATH\" >> \"$LOG_FILE\"\necho \"[SwiftLint] Working directory: $(pwd)\" >> \"$LOG_FILE\"\necho \"[SwiftLint] SRCROOT: ${SRCROOT}\" >> \"$LOG_FILE\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\" >> \"$LOG_FILE\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\" >> \"$LOG_FILE\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint >> \"$LOG_FILE\" 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\" >> \"$LOG_FILE\"\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\" >> \"$LOG_FILE\"\nfi\n"; }; 833FD9F821C01333001F80EB /* ShellScript */ = { isa = PBXShellScriptBuildPhase; @@ -1321,7 +1321,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\n# Redirect all output to stderr so it's visible even with xcpretty\nexec >&2\n\necho \"[SwiftLint] Starting SwiftLint check...\"\necho \"[SwiftLint] PATH: $PATH\"\necho \"[SwiftLint] Working directory: $(pwd)\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\"\n if [ $SWIFTLINT_EXIT_CODE -ne 0 ]; then\n echo \"[SwiftLint] ERROR: SwiftLint found violations (exit code: $SWIFTLINT_EXIT_CODE)\"\n echo \"[SwiftLint] Build will fail due to SwiftLint errors.\"\n else\n echo \"[SwiftLint] SUCCESS: SwiftLint passed with no violations.\"\n fi\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\"\nfi\n"; + shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\n# Write to a file in the workspace that persists after build\nLOG_FILE=\"${SRCROOT}/swiftlint_build_output.log\"\n\necho \"[SwiftLint] Starting SwiftLint check...\" >> \"$LOG_FILE\"\necho \"[SwiftLint] PATH: $PATH\" >> \"$LOG_FILE\"\necho \"[SwiftLint] Working directory: $(pwd)\" >> \"$LOG_FILE\"\necho \"[SwiftLint] SRCROOT: ${SRCROOT}\" >> \"$LOG_FILE\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\" >> \"$LOG_FILE\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\" >> \"$LOG_FILE\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint >> \"$LOG_FILE\" 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\" >> \"$LOG_FILE\"\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\" >> \"$LOG_FILE\"\nfi\n"; }; 83411A561FABCA2200E5CF39 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; @@ -1350,7 +1350,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\n# Redirect all output to stderr so it's visible even with xcpretty\nexec >&2\n\necho \"[SwiftLint] Starting SwiftLint check...\"\necho \"[SwiftLint] PATH: $PATH\"\necho \"[SwiftLint] Working directory: $(pwd)\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\"\n if [ $SWIFTLINT_EXIT_CODE -ne 0 ]; then\n echo \"[SwiftLint] ERROR: SwiftLint found violations (exit code: $SWIFTLINT_EXIT_CODE)\"\n echo \"[SwiftLint] Build will fail due to SwiftLint errors.\"\n else\n echo \"[SwiftLint] SUCCESS: SwiftLint passed with no violations.\"\n fi\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\"\nfi\n"; + shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\n# Write to a file in the workspace that persists after build\nLOG_FILE=\"${SRCROOT}/swiftlint_build_output.log\"\n\necho \"[SwiftLint] Starting SwiftLint check...\" >> \"$LOG_FILE\"\necho \"[SwiftLint] PATH: $PATH\" >> \"$LOG_FILE\"\necho \"[SwiftLint] Working directory: $(pwd)\" >> \"$LOG_FILE\"\necho \"[SwiftLint] SRCROOT: ${SRCROOT}\" >> \"$LOG_FILE\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\" >> \"$LOG_FILE\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\" >> \"$LOG_FILE\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint >> \"$LOG_FILE\" 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\" >> \"$LOG_FILE\"\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\" >> \"$LOG_FILE\"\nfi\n"; }; /* End PBXShellScriptBuildPhase section */ From 59bf6f024a8151ef118b3b1278ac2860e2043c65 Mon Sep 17 00:00:00 2001 From: Todd Anderson Date: Fri, 16 Jan 2026 16:48:28 -0500 Subject: [PATCH 12/20] updating to use system swiftlint instead of mint swiftlint by default --- LaunchDarkly.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/LaunchDarkly.xcodeproj/project.pbxproj b/LaunchDarkly.xcodeproj/project.pbxproj index 16ba6d8a..735bf245 100644 --- a/LaunchDarkly.xcodeproj/project.pbxproj +++ b/LaunchDarkly.xcodeproj/project.pbxproj @@ -1288,7 +1288,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\n# Write to a file in the workspace that persists after build\nLOG_FILE=\"${SRCROOT}/swiftlint_build_output.log\"\n\necho \"[SwiftLint] Starting SwiftLint check...\" >> \"$LOG_FILE\"\necho \"[SwiftLint] PATH: $PATH\" >> \"$LOG_FILE\"\necho \"[SwiftLint] Working directory: $(pwd)\" >> \"$LOG_FILE\"\necho \"[SwiftLint] SRCROOT: ${SRCROOT}\" >> \"$LOG_FILE\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\" >> \"$LOG_FILE\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\" >> \"$LOG_FILE\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint >> \"$LOG_FILE\" 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\" >> \"$LOG_FILE\"\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\" >> \"$LOG_FILE\"\nfi\n"; + shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\n# Write to a file in the workspace that persists after build\nLOG_FILE=\"${SRCROOT}/swiftlint_build_output.log\"\n\necho \"[SwiftLint] Starting SwiftLint check...\" >> \"$LOG_FILE\"\necho \"[SwiftLint] PATH: $PATH\" >> \"$LOG_FILE\"\necho \"[SwiftLint] Working directory: $(pwd)\" >> \"$LOG_FILE\"\necho \"[SwiftLint] SRCROOT: ${SRCROOT}\" >> \"$LOG_FILE\"\n\n# Try system swiftlint first (installed via brew in CI), fall back to mint\nif command -v swiftlint >/dev/null 2>&1; then\n SWIFTLINT_CMD=$(command -v swiftlint)\n echo \"[SwiftLint] Using system swiftlint at: $SWIFTLINT_CMD\" >> \"$LOG_FILE\"\n set +e\n \"$SWIFTLINT_CMD\" >> \"$LOG_FILE\" 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\" >> \"$LOG_FILE\"\n exit $SWIFTLINT_EXIT_CODE\nelif which mint >/dev/null; then\n echo \"[SwiftLint] Using mint, found at: $(which mint)\" >> \"$LOG_FILE\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\" >> \"$LOG_FILE\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint >> \"$LOG_FILE\" 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\" >> \"$LOG_FILE\"\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: Neither swiftlint nor mint found. SwiftLint check skipped.\" >> \"$LOG_FILE\"\n echo \"warning: Install swiftlint via 'brew install swiftlint' or mint via 'brew install mint'\"\nfi\n"; }; 830C2AC2207416A5001D645D /* Run Script */ = { isa = PBXShellScriptBuildPhase; @@ -1303,7 +1303,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\n# Write to a file in the workspace that persists after build\nLOG_FILE=\"${SRCROOT}/swiftlint_build_output.log\"\n\necho \"[SwiftLint] Starting SwiftLint check...\" >> \"$LOG_FILE\"\necho \"[SwiftLint] PATH: $PATH\" >> \"$LOG_FILE\"\necho \"[SwiftLint] Working directory: $(pwd)\" >> \"$LOG_FILE\"\necho \"[SwiftLint] SRCROOT: ${SRCROOT}\" >> \"$LOG_FILE\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\" >> \"$LOG_FILE\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\" >> \"$LOG_FILE\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint >> \"$LOG_FILE\" 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\" >> \"$LOG_FILE\"\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\" >> \"$LOG_FILE\"\nfi\n"; + shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\n# Write to a file in the workspace that persists after build\nLOG_FILE=\"${SRCROOT}/swiftlint_build_output.log\"\n\necho \"[SwiftLint] Starting SwiftLint check...\" >> \"$LOG_FILE\"\necho \"[SwiftLint] PATH: $PATH\" >> \"$LOG_FILE\"\necho \"[SwiftLint] Working directory: $(pwd)\" >> \"$LOG_FILE\"\necho \"[SwiftLint] SRCROOT: ${SRCROOT}\" >> \"$LOG_FILE\"\n\n# Try system swiftlint first (installed via brew in CI), fall back to mint\nif command -v swiftlint >/dev/null 2>&1; then\n SWIFTLINT_CMD=$(command -v swiftlint)\n echo \"[SwiftLint] Using system swiftlint at: $SWIFTLINT_CMD\" >> \"$LOG_FILE\"\n set +e\n \"$SWIFTLINT_CMD\" >> \"$LOG_FILE\" 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\" >> \"$LOG_FILE\"\n exit $SWIFTLINT_EXIT_CODE\nelif which mint >/dev/null; then\n echo \"[SwiftLint] Using mint, found at: $(which mint)\" >> \"$LOG_FILE\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\" >> \"$LOG_FILE\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint >> \"$LOG_FILE\" 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\" >> \"$LOG_FILE\"\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: Neither swiftlint nor mint found. SwiftLint check skipped.\" >> \"$LOG_FILE\"\n echo \"warning: Install swiftlint via 'brew install swiftlint' or mint via 'brew install mint'\"\nfi\n"; }; 833FD9F821C01333001F80EB /* ShellScript */ = { isa = PBXShellScriptBuildPhase; @@ -1321,7 +1321,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\n# Write to a file in the workspace that persists after build\nLOG_FILE=\"${SRCROOT}/swiftlint_build_output.log\"\n\necho \"[SwiftLint] Starting SwiftLint check...\" >> \"$LOG_FILE\"\necho \"[SwiftLint] PATH: $PATH\" >> \"$LOG_FILE\"\necho \"[SwiftLint] Working directory: $(pwd)\" >> \"$LOG_FILE\"\necho \"[SwiftLint] SRCROOT: ${SRCROOT}\" >> \"$LOG_FILE\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\" >> \"$LOG_FILE\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\" >> \"$LOG_FILE\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint >> \"$LOG_FILE\" 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\" >> \"$LOG_FILE\"\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\" >> \"$LOG_FILE\"\nfi\n"; + shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\n# Write to a file in the workspace that persists after build\nLOG_FILE=\"${SRCROOT}/swiftlint_build_output.log\"\n\necho \"[SwiftLint] Starting SwiftLint check...\" >> \"$LOG_FILE\"\necho \"[SwiftLint] PATH: $PATH\" >> \"$LOG_FILE\"\necho \"[SwiftLint] Working directory: $(pwd)\" >> \"$LOG_FILE\"\necho \"[SwiftLint] SRCROOT: ${SRCROOT}\" >> \"$LOG_FILE\"\n\n# Try system swiftlint first (installed via brew in CI), fall back to mint\nif command -v swiftlint >/dev/null 2>&1; then\n SWIFTLINT_CMD=$(command -v swiftlint)\n echo \"[SwiftLint] Using system swiftlint at: $SWIFTLINT_CMD\" >> \"$LOG_FILE\"\n set +e\n \"$SWIFTLINT_CMD\" >> \"$LOG_FILE\" 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\" >> \"$LOG_FILE\"\n exit $SWIFTLINT_EXIT_CODE\nelif which mint >/dev/null; then\n echo \"[SwiftLint] Using mint, found at: $(which mint)\" >> \"$LOG_FILE\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\" >> \"$LOG_FILE\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint >> \"$LOG_FILE\" 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\" >> \"$LOG_FILE\"\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: Neither swiftlint nor mint found. SwiftLint check skipped.\" >> \"$LOG_FILE\"\n echo \"warning: Install swiftlint via 'brew install swiftlint' or mint via 'brew install mint'\"\nfi\n"; }; 83411A561FABCA2200E5CF39 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; @@ -1350,7 +1350,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\n# Write to a file in the workspace that persists after build\nLOG_FILE=\"${SRCROOT}/swiftlint_build_output.log\"\n\necho \"[SwiftLint] Starting SwiftLint check...\" >> \"$LOG_FILE\"\necho \"[SwiftLint] PATH: $PATH\" >> \"$LOG_FILE\"\necho \"[SwiftLint] Working directory: $(pwd)\" >> \"$LOG_FILE\"\necho \"[SwiftLint] SRCROOT: ${SRCROOT}\" >> \"$LOG_FILE\"\n\nif which mint >/dev/null; then\n echo \"[SwiftLint] Found mint at: $(which mint)\" >> \"$LOG_FILE\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\" >> \"$LOG_FILE\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint >> \"$LOG_FILE\" 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\" >> \"$LOG_FILE\"\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\" >> \"$LOG_FILE\"\nfi\n"; + shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\n# Write to a file in the workspace that persists after build\nLOG_FILE=\"${SRCROOT}/swiftlint_build_output.log\"\n\necho \"[SwiftLint] Starting SwiftLint check...\" >> \"$LOG_FILE\"\necho \"[SwiftLint] PATH: $PATH\" >> \"$LOG_FILE\"\necho \"[SwiftLint] Working directory: $(pwd)\" >> \"$LOG_FILE\"\necho \"[SwiftLint] SRCROOT: ${SRCROOT}\" >> \"$LOG_FILE\"\n\n# Try system swiftlint first (installed via brew in CI), fall back to mint\nif command -v swiftlint >/dev/null 2>&1; then\n SWIFTLINT_CMD=$(command -v swiftlint)\n echo \"[SwiftLint] Using system swiftlint at: $SWIFTLINT_CMD\" >> \"$LOG_FILE\"\n set +e\n \"$SWIFTLINT_CMD\" >> \"$LOG_FILE\" 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\" >> \"$LOG_FILE\"\n exit $SWIFTLINT_EXIT_CODE\nelif which mint >/dev/null; then\n echo \"[SwiftLint] Using mint, found at: $(which mint)\" >> \"$LOG_FILE\"\n echo \"[SwiftLint] Running: /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint\" >> \"$LOG_FILE\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run realm/SwiftLint >> \"$LOG_FILE\" 2>&1\n SWIFTLINT_EXIT_CODE=$?\n set -e\n echo \"[SwiftLint] Exit code: $SWIFTLINT_EXIT_CODE\" >> \"$LOG_FILE\"\n exit $SWIFTLINT_EXIT_CODE\nelse\n echo \"warning: Neither swiftlint nor mint found. SwiftLint check skipped.\" >> \"$LOG_FILE\"\n echo \"warning: Install swiftlint via 'brew install swiftlint' or mint via 'brew install mint'\"\nfi\n"; }; /* End PBXShellScriptBuildPhase section */ From 45d2c9fb6f0d10a9f6eea4ae6dc1c66398cebaac Mon Sep 17 00:00:00 2001 From: Todd Anderson Date: Tue, 20 Jan 2026 09:39:53 -0500 Subject: [PATCH 13/20] addressing more swift lint issues triggered in build script --- LaunchDarkly/LaunchDarkly/LDClient.swift | 1 + LaunchDarkly/LaunchDarkly/Networking/DarklyService.swift | 1 + 2 files changed, 2 insertions(+) diff --git a/LaunchDarkly/LaunchDarkly/LDClient.swift b/LaunchDarkly/LaunchDarkly/LDClient.swift index 68b927c4..d7961bce 100644 --- a/LaunchDarkly/LaunchDarkly/LDClient.swift +++ b/LaunchDarkly/LaunchDarkly/LDClient.swift @@ -36,6 +36,7 @@ enum LDClientRunMode { ``` The `changedFlag` passed in to the closure contains the old and new value of the flag. */ +// swiftlint:disable:next type_body_length public class LDClient { // MARK: - State Controls and Indicators diff --git a/LaunchDarkly/LaunchDarkly/Networking/DarklyService.swift b/LaunchDarkly/LaunchDarkly/Networking/DarklyService.swift index a858adbc..5b7872e1 100644 --- a/LaunchDarkly/LaunchDarkly/Networking/DarklyService.swift +++ b/LaunchDarkly/LaunchDarkly/Networking/DarklyService.swift @@ -3,6 +3,7 @@ import LDSwiftEventSource import OSLog import DataCompression +// swiftlint:disable:next large_tuple typealias ServiceResponse = (data: Data?, urlResponse: URLResponse?, error: Error?, etag: String?) typealias ServiceCompletionHandler = (ServiceResponse) -> Void From 6fa75cf0f63f989448b45fdf11b80160dd2ea7e9 Mon Sep 17 00:00:00 2001 From: Todd Anderson Date: Tue, 20 Jan 2026 09:54:51 -0500 Subject: [PATCH 14/20] swiftlint suppression tweak --- LaunchDarkly/LaunchDarkly/LDClient.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/LaunchDarkly/LaunchDarkly/LDClient.swift b/LaunchDarkly/LaunchDarkly/LDClient.swift index d7961bce..682c5b5d 100644 --- a/LaunchDarkly/LaunchDarkly/LDClient.swift +++ b/LaunchDarkly/LaunchDarkly/LDClient.swift @@ -34,9 +34,9 @@ enum LDClientRunMode { self?.updateFlag(key: "flag-key", changedFlag: changedFlag) } ``` - The `changedFlag` passed in to the closure contains the old and new value of the flag. - */ -// swiftlint:disable:next type_body_length +The `changedFlag` passed in to the closure contains the old and new value of the flag. +*/ +// swiftlint:disable type_body_length missing_docs public class LDClient { // MARK: - State Controls and Indicators From bda502fdb219463e71574847cd23229f69e84baf Mon Sep 17 00:00:00 2001 From: Todd Anderson Date: Tue, 20 Jan 2026 10:11:41 -0500 Subject: [PATCH 15/20] now fixing swiftlint issues in tests --- .../LDClientEvaluationHookSpec.swift | 4 +++- .../LaunchDarklyTests/LDClientPluginsSpec.swift | 4 +++- .../LaunchDarklyTests/LDClientSpec.swift | 17 +++++++++++++---- .../LaunchDarklyTests/LDValueDecoderSpec.swift | 14 +++++++++++--- .../Mocks/ClientServiceMockFactory.swift | 8 +++++++- .../Networking/DarklyServiceSpec.swift | 15 ++++++++++++--- .../Networking/HTTPHeadersSpec.swift | 4 +++- .../ServiceObjects/FlagSynchronizerSpec.swift | 5 ++++- 8 files changed, 56 insertions(+), 15 deletions(-) diff --git a/LaunchDarkly/LaunchDarklyTests/LDClientEvaluationHookSpec.swift b/LaunchDarkly/LaunchDarklyTests/LDClientEvaluationHookSpec.swift index 633e95ca..6434a28d 100644 --- a/LaunchDarkly/LaunchDarklyTests/LDClientEvaluationHookSpec.swift +++ b/LaunchDarkly/LaunchDarklyTests/LDClientEvaluationHookSpec.swift @@ -117,7 +117,9 @@ final class LDClientEvaluationHookSpec: XCTestCase { return self.before(seriesContext, seriesData) } - func afterEvaluation(seriesContext: LaunchDarkly.EvaluationSeriesContext, seriesData: LaunchDarkly.EvaluationSeriesData, evaluationDetail: LaunchDarkly.LDEvaluationDetail) -> LaunchDarkly.EvaluationSeriesData { + func afterEvaluation(seriesContext: LaunchDarkly.EvaluationSeriesContext, + seriesData: LaunchDarkly.EvaluationSeriesData, + evaluationDetail: LaunchDarkly.LDEvaluationDetail) -> LaunchDarkly.EvaluationSeriesData { return self.after(seriesContext, seriesData, evaluationDetail) } } diff --git a/LaunchDarkly/LaunchDarklyTests/LDClientPluginsSpec.swift b/LaunchDarkly/LaunchDarklyTests/LDClientPluginsSpec.swift index 08bfca00..0f072f8b 100644 --- a/LaunchDarkly/LaunchDarklyTests/LDClientPluginsSpec.swift +++ b/LaunchDarkly/LaunchDarklyTests/LDClientPluginsSpec.swift @@ -133,7 +133,9 @@ final class LDClientPluginsSpec: XCTestCase { return self.before(seriesContext, seriesData) } - func afterEvaluation(seriesContext: LaunchDarkly.EvaluationSeriesContext, seriesData: LaunchDarkly.EvaluationSeriesData, evaluationDetail: LaunchDarkly.LDEvaluationDetail) -> LaunchDarkly.EvaluationSeriesData { + func afterEvaluation(seriesContext: LaunchDarkly.EvaluationSeriesContext, + seriesData: LaunchDarkly.EvaluationSeriesData, + evaluationDetail: LaunchDarkly.LDEvaluationDetail) -> LaunchDarkly.EvaluationSeriesData { return self.after(seriesContext, seriesData, evaluationDetail) } } diff --git a/LaunchDarkly/LaunchDarklyTests/LDClientSpec.swift b/LaunchDarkly/LaunchDarklyTests/LDClientSpec.swift index 7590ae2e..abb04e8e 100644 --- a/LaunchDarkly/LaunchDarklyTests/LDClientSpec.swift +++ b/LaunchDarkly/LaunchDarklyTests/LDClientSpec.swift @@ -742,9 +742,12 @@ final class LDClientSpec: QuickSpec { expect(testContext.eventReporterMock.recordFlagEvaluationEventsCallCount) == 1 expect(testContext.eventReporterMock.recordFlagEvaluationEventsReceivedArguments?.flagKey) == DarklyServiceMock.FlagKeys.bool expect(testContext.eventReporterMock.recordFlagEvaluationEventsReceivedArguments?.value) == DarklyServiceMock.FlagValues.bool - expect(testContext.eventReporterMock.recordFlagEvaluationEventsReceivedArguments?.defaultValue) == .bool(DefaultFlagValues.bool) - expect(testContext.eventReporterMock.recordFlagEvaluationEventsReceivedArguments?.featureFlag) == testContext.flagStoreMock.storedItems.featureFlags[DarklyServiceMock.FlagKeys.bool] - expect(testContext.eventReporterMock.recordFlagEvaluationEventsReceivedArguments?.context) == testContext.context + expect(testContext.eventReporterMock.recordFlagEvaluationEventsReceivedArguments?.defaultValue) == + .bool(DefaultFlagValues.bool) + expect(testContext.eventReporterMock.recordFlagEvaluationEventsReceivedArguments?.featureFlag) == + testContext.flagStoreMock.storedItems.featureFlags[DarklyServiceMock.FlagKeys.bool] + expect(testContext.eventReporterMock.recordFlagEvaluationEventsReceivedArguments?.context) == + testContext.context } } } @@ -781,7 +784,13 @@ final class LDClientSpec: QuickSpec { var events = [FeatureEvent]() testContext.eventReporterMock.recordFlagEvaluationEventsCallback = { let args = testContext.eventReporterMock.recordFlagEvaluationEventsReceivedArguments! - let event = FeatureEvent(key: args.flagKey, context: args.context, value: args.value, defaultValue: args.defaultValue, featureFlag: args.featureFlag, includeReason: args.includeReason, isDebug: false) + let event = FeatureEvent(key: args.flagKey, + context: args.context, + value: args.value, + defaultValue: args.defaultValue, + featureFlag: args.featureFlag, + includeReason: args.includeReason, + isDebug: false) events.append(event) } _ = testContext.subject.boolVariation(forKey: "flagA", defaultValue: DefaultFlagValues.bool) diff --git a/LaunchDarkly/LaunchDarklyTests/LDValueDecoderSpec.swift b/LaunchDarkly/LaunchDarklyTests/LDValueDecoderSpec.swift index 2a65532c..f5232846 100644 --- a/LaunchDarkly/LaunchDarklyTests/LDValueDecoderSpec.swift +++ b/LaunchDarkly/LaunchDarklyTests/LDValueDecoderSpec.swift @@ -89,17 +89,25 @@ final class LDValueDecoderSpec: XCTestCase { let container = try decoder.container(keyedBy: DynamicCodingKeys.self) guard case .some(let bio) = try container.decodeIfPresent([String: String].self, forKey: DynamicCodingKeys(string: "bio")) else { - throw DecodingError.valueNotFound([String: String].self, DecodingError.Context(codingPath: [DynamicCodingKeys(string: "bio")], debugDescription: "bio must be present and a dictionary of strings")) + throw DecodingError.valueNotFound([String: String].self, + DecodingError.Context(codingPath: [DynamicCodingKeys(string: "bio")], + debugDescription: "bio must be present and a dictionary of strings")) } guard let firstName = bio["firstName"] else { - throw DecodingError.valueNotFound(String.self, DecodingError.Context(codingPath: [DynamicCodingKeys(string: "bio"), DynamicCodingKeys(string: "firstName")], debugDescription: "bio must contain first name")) + throw DecodingError.valueNotFound(String.self, + DecodingError.Context(codingPath: [DynamicCodingKeys(string: "bio"), + DynamicCodingKeys(string: "firstName")], + debugDescription: "bio must contain first name")) } self.firstName = firstName guard let lastName = bio["lastName"] else { - throw DecodingError.valueNotFound(String.self, DecodingError.Context(codingPath: [DynamicCodingKeys(string: "bio"), DynamicCodingKeys(string: "lastName")], debugDescription: "bio must contain last name")) + throw DecodingError.valueNotFound(String.self, + DecodingError.Context(codingPath: [DynamicCodingKeys(string: "bio"), + DynamicCodingKeys(string: "lastName")], + debugDescription: "bio must contain last name")) } self.lastName = lastName diff --git a/LaunchDarkly/LaunchDarklyTests/Mocks/ClientServiceMockFactory.swift b/LaunchDarkly/LaunchDarklyTests/Mocks/ClientServiceMockFactory.swift index d954e4fd..26686f28 100644 --- a/LaunchDarkly/LaunchDarklyTests/Mocks/ClientServiceMockFactory.swift +++ b/LaunchDarkly/LaunchDarklyTests/Mocks/ClientServiceMockFactory.swift @@ -91,7 +91,13 @@ final class ClientServiceMockFactory: ClientServiceCreating { handler: EventHandler, delegate: RequestHeaderTransform?, errorHandler: ConnectionErrorHandler?)? - func makeStreamingProvider(url: URL, httpHeaders: [String: String], connectMethod: String, connectBody: Data?, handler: EventHandler, delegate: RequestHeaderTransform?, errorHandler: ConnectionErrorHandler?) -> DarklyStreamingProvider { + func makeStreamingProvider(url: URL, + httpHeaders: [String: String], + connectMethod: String, + connectBody: Data?, + handler: EventHandler, + delegate: RequestHeaderTransform?, + errorHandler: ConnectionErrorHandler?) -> DarklyStreamingProvider { makeStreamingProviderCallCount += 1 makeStreamingProviderReceivedArguments = (url, httpHeaders, connectMethod, connectBody, handler, delegate, errorHandler) return DarklyStreamingProviderMock() diff --git a/LaunchDarkly/LaunchDarklyTests/Networking/DarklyServiceSpec.swift b/LaunchDarkly/LaunchDarklyTests/Networking/DarklyServiceSpec.swift index c0130b90..19611a6e 100644 --- a/LaunchDarkly/LaunchDarklyTests/Networking/DarklyServiceSpec.swift +++ b/LaunchDarkly/LaunchDarklyTests/Networking/DarklyServiceSpec.swift @@ -112,7 +112,9 @@ final class DarklyServiceSpec: QuickSpec { expect(urlRequest?.url?.host) == testContext.config.baseUrl.host if let path = urlRequest?.url?.path { expect(path.hasPrefix("/\(DarklyService.FlagRequestPath.get)")).to(beTrue()) - let expectedContext = encodeToLDValue(testContext.context, userInfo: [LDContext.UserInfoKeys.includePrivateAttributes: true, LDContext.UserInfoKeys.redactAttributes: false]) + let expectedContext = encodeToLDValue(testContext.context, + userInfo: [LDContext.UserInfoKeys.includePrivateAttributes: true, + LDContext.UserInfoKeys.redactAttributes: false]) expect(urlRequest?.url?.lastPathComponent.jsonValue) == expectedContext } else { fail("request path is missing") @@ -165,7 +167,9 @@ final class DarklyServiceSpec: QuickSpec { expect(urlRequest?.url?.host) == testContext.config.baseUrl.host if let path = urlRequest?.url?.path { expect(path.hasPrefix("/\(DarklyService.FlagRequestPath.get)")).to(beTrue()) - let expectedContext = encodeToLDValue(testContext.context, userInfo: [LDContext.UserInfoKeys.includePrivateAttributes: true, LDContext.UserInfoKeys.redactAttributes: false]) + let expectedContext = encodeToLDValue(testContext.context, + userInfo: [LDContext.UserInfoKeys.includePrivateAttributes: true, + LDContext.UserInfoKeys.redactAttributes: false]) expect(urlRequest?.url?.lastPathComponent.jsonValue) == expectedContext } else { fail("request path is missing") @@ -665,7 +669,12 @@ final class DarklyServiceSpec: QuickSpec { } private func stubDiagnostic() -> DiagnosticStats { - DiagnosticStats(id: DiagnosticId(diagnosticId: "test-id", sdkKey: LDConfig.Constants.mockMobileKey), creationDate: 1000, dataSinceDate: 100, droppedEvents: 0, eventsInLastBatch: 0, streamInits: []) + DiagnosticStats(id: DiagnosticId(diagnosticId: "test-id", sdkKey: LDConfig.Constants.mockMobileKey), + creationDate: 1000, + dataSinceDate: 100, + droppedEvents: 0, + eventsInLastBatch: 0, + streamInits: []) } private func publishDiagnosticSpec() { diff --git a/LaunchDarkly/LaunchDarklyTests/Networking/HTTPHeadersSpec.swift b/LaunchDarkly/LaunchDarklyTests/Networking/HTTPHeadersSpec.swift index 4d93f26c..f3628ddc 100644 --- a/LaunchDarkly/LaunchDarklyTests/Networking/HTTPHeadersSpec.swift +++ b/LaunchDarkly/LaunchDarklyTests/Networking/HTTPHeadersSpec.swift @@ -111,7 +111,9 @@ final class HTTPHeadersSpec: XCTestCase { httpHeaders.eventRequestHeaders, httpHeaders.diagnosticRequestHeaders] allRequestTypes.forEach { headers in - XCTAssertEqual(headers["X-LaunchDarkly-Tags"], Optional("application-id/example-id application-name/example-name application-version/example-version application-version-name/example-version-name")) + XCTAssertEqual(headers["X-LaunchDarkly-Tags"], + Optional("application-id/example-id application-name/example-name " + + "application-version/example-version application-version-name/example-version-name")) } } } diff --git a/LaunchDarkly/LaunchDarklyTests/ServiceObjects/FlagSynchronizerSpec.swift b/LaunchDarkly/LaunchDarklyTests/ServiceObjects/FlagSynchronizerSpec.swift index 96669fed..373e5b2a 100644 --- a/LaunchDarkly/LaunchDarklyTests/ServiceObjects/FlagSynchronizerSpec.swift +++ b/LaunchDarkly/LaunchDarklyTests/ServiceObjects/FlagSynchronizerSpec.swift @@ -996,7 +996,10 @@ final class FlagSynchronizerSpec: QuickSpec { } describe("makeFlagRequest") { var testContext: TestContext! - // This test completes the test suite on makeFlagRequest by validating the method bails out if it's called and the synchronizer is offline. While that shouldn't happen, there are 2 code paths that don't directly verify the SDK is online before calling the method, so it seems a wise precaution to validate that the method does bailout. Other tests exercise the rest of the method. + // This test completes the test suite on makeFlagRequest by validating the method bails out if it's called + // and the synchronizer is offline. While that shouldn't happen, there are 2 code paths that don't directly + // verify the SDK is online before calling the method, so it seems a wise precaution to validate that the + // method does bailout. Other tests exercise the rest of the method. context("offline") { var synchronizingError: SynchronizingError? it("does not request flags and calls onSyncComplete with an isOffline error") { From 1912a801a57512db65eb43909b36a03306775655 Mon Sep 17 00:00:00 2001 From: Todd Anderson Date: Tue, 20 Jan 2026 10:43:00 -0500 Subject: [PATCH 16/20] logging sourcery errors --- .github/actions/ci/action.yml | 36 +++++++++++++++++--------- LaunchDarkly.xcodeproj/project.pbxproj | 2 +- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/.github/actions/ci/action.yml b/.github/actions/ci/action.yml index f197f240..b23f9318 100644 --- a/.github/actions/ci/action.yml +++ b/.github/actions/ci/action.yml @@ -57,18 +57,6 @@ runs: shell: bash run: xcodebuild build -scheme 'LaunchDarkly_macOS' -sdk macosx -destination 'platform=macOS' | xcpretty - - name: Display SwiftLint output (if build failed) - shell: bash - if: failure() - run: | - if [ -f swiftlint_build_output.log ]; then - echo "=== SwiftLint Build Script Output ===" - cat swiftlint_build_output.log - echo "=== End SwiftLint Output ===" - else - echo "No SwiftLint log file found" - fi - - name: Build Tests for iOS device shell: bash run: xcodebuild build-for-testing -scheme 'LaunchDarkly_iOS' -sdk iphoneos CODE_SIGN_IDENTITY= | xcpretty @@ -93,6 +81,30 @@ runs: shell: bash run: xcodebuild build -scheme 'LaunchDarkly_watchOS' -sdk watchos | xcpretty + - name: Display SwiftLint output (if build failed) + shell: bash + if: failure() + run: | + if [ -f swiftlint_build_output.log ]; then + echo "=== SwiftLint Build Script Output ===" + cat swiftlint_build_output.log + echo "=== End SwiftLint Output ===" + else + echo "No SwiftLint log file found" + fi + + - name: Display Sourcery output (if build failed) + shell: bash + if: failure() + run: | + if [ -f sourcery_build_output.log ]; then + echo "=== Sourcery Build Script Output ===" + cat sourcery_build_output.log + echo "=== End Sourcery Output ===" + else + echo "No Sourcery log file found" + fi + - name: Build & Test with swiftpm shell: bash run: swift test -v diff --git a/LaunchDarkly.xcodeproj/project.pbxproj b/LaunchDarkly.xcodeproj/project.pbxproj index 735bf245..ff4bbabf 100644 --- a/LaunchDarkly.xcodeproj/project.pbxproj +++ b/LaunchDarkly.xcodeproj/project.pbxproj @@ -1335,7 +1335,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\nif which mint >/dev/null; then\n /usr/bin/xcrun --sdk macosx mint run krzysztofzablocki/Sourcery\nelse\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\"\nfi\n"; + shellScript = "# Adds support for Apple Silicon brew directory\nexport PATH=\"$PATH:/opt/homebrew/bin\"\n\n# Write to a file in the workspace that persists after build\nLOG_FILE=\"${SRCROOT}/sourcery_build_output.log\"\n\necho \"[Sourcery] Starting Sourcery code generation...\" >> \"$LOG_FILE\"\necho \"[Sourcery] Timestamp: $(date)\" >> \"$LOG_FILE\"\necho \"[Sourcery] PATH: $PATH\" >> \"$LOG_FILE\"\necho \"[Sourcery] Working directory: $(pwd)\" >> \"$LOG_FILE\"\necho \"[Sourcery] SRCROOT: ${SRCROOT}\" >> \"$LOG_FILE\"\necho \"[Sourcery] XCODE_PRODUCT_BUILD_VERSION: ${XCODE_PRODUCT_BUILD_VERSION}\" >> \"$LOG_FILE\"\n\nif which mint >/dev/null 2>&1; then\n MINT_CMD=$(which mint)\n echo \"[Sourcery] Using mint, found at: $MINT_CMD\" >> \"$LOG_FILE\"\n echo \"[Sourcery] Running: /usr/bin/xcrun --sdk macosx mint run krzysztofzablocki/Sourcery\" >> \"$LOG_FILE\"\n set +e\n /usr/bin/xcrun --sdk macosx mint run krzysztofzablocki/Sourcery >> \"$LOG_FILE\" 2>&1\n SOURCERY_EXIT_CODE=$?\n set -e\n echo \"[Sourcery] Exit code: $SOURCERY_EXIT_CODE\" >> \"$LOG_FILE\"\n if [ $SOURCERY_EXIT_CODE -ne 0 ]; then\n echo \"[Sourcery] ERROR: Sourcery failed with exit code $SOURCERY_EXIT_CODE\" >> \"$LOG_FILE\"\n echo \"[Sourcery] Check $LOG_FILE for details\"\n else\n echo \"[Sourcery] Successfully completed\" >> \"$LOG_FILE\"\n fi\n exit $SOURCERY_EXIT_CODE\nelse\n echo \"[Sourcery] ERROR: mint not found in PATH\" >> \"$LOG_FILE\"\n echo \"[Sourcery] PATH was: $PATH\" >> \"$LOG_FILE\"\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\"\n echo \"warning: mint not installed, available from https://github.com/yonaskolb/Mint\" >> \"$LOG_FILE\"\n exit 1\nfi\n"; }; 835E1CFE1F61AC0600184DB4 /* Run Script */ = { isa = PBXShellScriptBuildPhase; From 7f65684bc0fee171837f3908c338dc83127b3b94 Mon Sep 17 00:00:00 2001 From: Todd Anderson Date: Tue, 20 Jan 2026 11:11:20 -0500 Subject: [PATCH 17/20] bumping sourcery version to incorporate fputs fix --- .github/actions/ci/action.yml | 5 ----- Mintfile | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/actions/ci/action.yml b/.github/actions/ci/action.yml index b23f9318..ee9a77ec 100644 --- a/.github/actions/ci/action.yml +++ b/.github/actions/ci/action.yml @@ -29,11 +29,6 @@ runs: run: | brew install mint - - name: Install swiftlint - shell: bash - run: | - brew install swiftlint - - name: Install cocoapods shell: bash run: gem install cocoapods diff --git a/Mintfile b/Mintfile index 8414be05..64a43d62 100644 --- a/Mintfile +++ b/Mintfile @@ -1,2 +1,2 @@ -realm/SwiftLint@0.43.1 -krzysztofzablocki/Sourcery@1.2.1 +realm/SwiftLint@0.63.0 +krzysztofzablocki/Sourcery@2.3.0 From 0a57735677062958ec97bf1ac1f456ab95f2eb31 Mon Sep 17 00:00:00 2001 From: Todd Anderson Date: Tue, 20 Jan 2026 11:26:32 -0500 Subject: [PATCH 18/20] more --- .github/actions/ci/action.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/actions/ci/action.yml b/.github/actions/ci/action.yml index ee9a77ec..b23f9318 100644 --- a/.github/actions/ci/action.yml +++ b/.github/actions/ci/action.yml @@ -29,6 +29,11 @@ runs: run: | brew install mint + - name: Install swiftlint + shell: bash + run: | + brew install swiftlint + - name: Install cocoapods shell: bash run: gem install cocoapods From 6d4d8a86355f3ded5842907d00b9d585f7674241 Mon Sep 17 00:00:00 2001 From: Todd Anderson Date: Tue, 20 Jan 2026 14:28:32 -0500 Subject: [PATCH 19/20] bumping contract tests platform macos version --- ContractTests/Package.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ContractTests/Package.swift b/ContractTests/Package.swift index 59c2b8e8..82d0d3d9 100644 --- a/ContractTests/Package.swift +++ b/ContractTests/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.5 import PackageDescription @@ -6,7 +6,7 @@ let package = Package( name: "ContractTests", platforms: [ .iOS(.v12), - .macOS(.v10_15), + .macOS(.v12), .watchOS(.v4), .tvOS(.v12) ], From 7a4a27753c610fd12e8d328396e1ba71a5ac6fb6 Mon Sep 17 00:00:00 2001 From: Todd Anderson Date: Thu, 22 Jan 2026 16:36:40 -0500 Subject: [PATCH 20/20] tweaking test to fix failure on macos-15 runner --- .../Networking/DarklyServiceSpec.swift | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/LaunchDarkly/LaunchDarklyTests/Networking/DarklyServiceSpec.swift b/LaunchDarkly/LaunchDarklyTests/Networking/DarklyServiceSpec.swift index 19611a6e..dd752de2 100644 --- a/LaunchDarkly/LaunchDarklyTests/Networking/DarklyServiceSpec.swift +++ b/LaunchDarkly/LaunchDarklyTests/Networking/DarklyServiceSpec.swift @@ -608,11 +608,17 @@ final class DarklyServiceSpec: QuickSpec { context("failure") { var responses: ServiceResponses! beforeEach { + // Set up stub before waitUntil to ensure it's registered before the request is made. + // On macOS 15/Xcode 16, OHHTTPStubs error responses may not immediately trigger + // the completion handler, so we ensure the stub is ready first. + testContext.serviceMock.stubEventRequest(success: false) { eventRequest = $0 } waitUntil { done in - testContext.serviceMock.stubEventRequest(success: false) { eventRequest = $0 } testContext.service.publishEventData(testData, UUID().uuidString) { response in responses = (response.data, response.urlResponse, response.error) - done() + // Ensure done() is called on the main queue, as waitUntil may require it + DispatchQueue.main.async { + done() + } } } } @@ -721,11 +727,17 @@ final class DarklyServiceSpec: QuickSpec { context("failure") { var responses: ServiceResponses! beforeEach { + // Set up stub before waitUntil to ensure it's registered before the request is made. + // On macOS 15/Xcode 16, OHHTTPStubs error responses may not immediately trigger + // the completion handler, so we ensure the stub is ready first. + testContext.serviceMock.stubEventRequest(success: false) { diagnosticRequest = $0 } waitUntil { done in - testContext.serviceMock.stubEventRequest(success: false) { diagnosticRequest = $0 } testContext.service.publishDiagnostic(diagnosticEvent: self.stubDiagnostic()) { response in responses = (response.data, response.urlResponse, response.error) - done() + // Ensure done() is called on the main queue, as waitUntil may require it + DispatchQueue.main.async { + done() + } } } }