Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion .github/actions/ci/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,25 @@ runs:
run: |
brew install mint

- name: Install swiftlint
shell: bash
run: |
brew install swiftlint

- name: Install cocoapods
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

- name: Run swiftlint
- name: Run swiftlint on ContractTests
shell: bash
run: |
cd ./ContractTests
Expand Down Expand Up @@ -71,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
Expand Down
2 changes: 1 addition & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -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**
Expand Down
16 changes: 8 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -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'

Expand All @@ -17,13 +17,13 @@ jobs:
fail-fast: false
matrix:
include:
- xcode-version: 15.0.1
ios-sim: 'platform=iOS Simulator,name=iPhone 15,OS=17.2'
os: macos-13
- xcode-version: 16.4.0
ios-sim: 'platform=iOS Simulator,name=iPhone 16'
os: macos-15
run-contract-tests: true
- xcode-version: 14.3.1
ios-sim: 'platform=iOS Simulator,name=iPhone 14,OS=16.4'
os: macos-13
- xcode-version: 15.4.0
ios-sim: 'platform=iOS Simulator,name=iPhone 15'
os: macos-14
run-contract-tests: false

steps:
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/manual-publish-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -16,8 +16,8 @@ jobs:
- name: Build and Test
uses: ./.github/actions/ci
with:
xcode-version: 15.0.1
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 }}

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/manual-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ on:

jobs:
build-publish:
runs-on: macos-14
runs-on: macos-15

# Needed to get tokens during publishing.
permissions:
Expand All @@ -27,8 +27,8 @@ jobs:

- uses: ./.github/actions/ci
with:
xcode-version: 15.0.1
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 }}

Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/release-please.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ on:
workflow_dispatch:
push:
branches:
- v9
- v10

jobs:
release-package:
runs-on: macos-14
runs-on: macos-15

permissions:
id-token: write # Needed if using OIDC to get release secrets.
Expand Down Expand Up @@ -46,8 +46,8 @@ jobs:
- uses: ./.github/actions/ci
if: ${{ steps.release.outputs.releases_created == 'true' }}
with:
xcode-version: 15.0.1
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 }}

Expand Down
4 changes: 2 additions & 2 deletions ContractTests/Package.swift
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// swift-tools-version:5.3
// swift-tools-version:5.5

import PackageDescription

let package = Package(
name: "ContractTests",
platforms: [
.iOS(.v12),
.macOS(.v10_15),
.macOS(.v12),
.watchOS(.v4),
.tvOS(.v12)
],
Expand Down
42 changes: 33 additions & 9 deletions LaunchDarkly.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

10 changes: 6 additions & 4 deletions LaunchDarkly/LaunchDarkly/LDClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +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.
*/
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
Expand Down Expand Up @@ -332,6 +333,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()
Expand All @@ -352,7 +354,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.
Expand Down Expand Up @@ -384,7 +386,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)
}

Expand Down
13 changes: 7 additions & 6 deletions LaunchDarkly/LaunchDarkly/LDClientIdentifyHook.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -16,31 +16,32 @@ 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
hook.beforeIdentify(seriesContext: seriesContext, seriesData: EvaluationSeriesData())
}
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
Expand Down
11 changes: 7 additions & 4 deletions LaunchDarkly/LaunchDarkly/Models/Hooks/Hook.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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()`.
Expand All @@ -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()`.
Expand All @@ -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<LDValue>) -> 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`.
///
Expand All @@ -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.
Expand Down
1 change: 1 addition & 0 deletions LaunchDarkly/LaunchDarkly/Networking/DarklyService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ final class TimeoutExecutor {
}
return
}

let lockQueue = DispatchQueue(label: "launchdarkly.timeout.executor.lock")
var finished = false

Expand All @@ -52,7 +52,7 @@ final class TimeoutExecutor {
shouldCall = true
}
}

if shouldCall {
queue.async { completion(value) }
}
Expand All @@ -67,7 +67,7 @@ final class TimeoutExecutor {
shouldCall = true
}
}

if shouldCall {
completion(timeoutValue())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.LDValue>) -> LaunchDarkly.EvaluationSeriesData {
func afterEvaluation(seriesContext: LaunchDarkly.EvaluationSeriesContext,
seriesData: LaunchDarkly.EvaluationSeriesData,
evaluationDetail: LaunchDarkly.LDEvaluationDetail<LaunchDarkly.LDValue>) -> LaunchDarkly.EvaluationSeriesData {
return self.after(seriesContext, seriesData, evaluationDetail)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 })
Expand Down
4 changes: 3 additions & 1 deletion LaunchDarkly/LaunchDarklyTests/LDClientPluginsSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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.LDValue>) -> LaunchDarkly.EvaluationSeriesData {
func afterEvaluation(seriesContext: LaunchDarkly.EvaluationSeriesContext,
seriesData: LaunchDarkly.EvaluationSeriesData,
evaluationDetail: LaunchDarkly.LDEvaluationDetail<LaunchDarkly.LDValue>) -> LaunchDarkly.EvaluationSeriesData {
return self.after(seriesContext, seriesData, evaluationDetail)
}
}
Expand Down
Loading