From 34c6a63ae52c1bbca61920ac69facc69aa407fce Mon Sep 17 00:00:00 2001
From: Mark Phelps <209477+markphelps@users.noreply.github.com>
Date: Wed, 30 Oct 2024 15:06:25 -0400
Subject: [PATCH] chore: Swift readme (#496)
* chore: add swift readme; add release scripts for swift and c#
* chore: update main README
Signed-off-by: Mark Phelps <209477+markphelps@users.noreply.github.com>
---------
Signed-off-by: Mark Phelps <209477+markphelps@users.noreply.github.com>
---
README.md | 2 +-
flipt-client-swift/README.md | 115 +++++++++++++++++++++++++++++++++++
release/release.py | 10 ++-
release/sdks/__init__.py | 2 +
release/sdks/csharp.py | 32 ++++++++++
release/sdks/swift.py | 29 +++++++++
6 files changed, 188 insertions(+), 2 deletions(-)
create mode 100644 flipt-client-swift/README.md
create mode 100644 release/sdks/csharp.py
create mode 100644 release/sdks/swift.py
diff --git a/README.md b/README.md
index bb5cc083..9be7c9f9 100644
--- a/README.md
+++ b/README.md
@@ -64,6 +64,7 @@ Currently, we support the following languages/platforms:
| [React Web (Browser)](./flipt-client-react) | WASM | N/A | N/A |
| [Flutter/Dart](./flipt-client-dart) | FFI | ✅ | ❌ |
| [C#](./flipt-client-csharp) | FFI | ✅ | ❌ |
+| [Swift](./flipt-client-swift) | FFI | N/A | N/A |
Documentation for each client can be found in the README of that client's directory.
@@ -78,7 +79,6 @@ Languages we are planning to support:
Languages we would like to support but lack expertise in:
1. [Kotlin](https://github.com/flipt-io/flipt-client-sdks/issues/264)
-1. [Swift](https://github.com/flipt-io/flipt-client-sdks/issues/263)
1. [React Native](https://github.com/flipt-io/flipt-client-sdks/issues/345)
Want to see a client in a language we don't support? [Open an issue](https://github.com/flipt-io/flipt-client-sdks/issues/new?assignees=&labels=new-language&projects=&template=new_language.yml) and let us know!
diff --git a/flipt-client-swift/README.md b/flipt-client-swift/README.md
new file mode 100644
index 00000000..3995518e
--- /dev/null
+++ b/flipt-client-swift/README.md
@@ -0,0 +1,115 @@
+# Flipt Client Swift
+
+[![GitHub Release](https://img.shields.io/github/v/release/flipt-io/flipt-client-sdks?filter=flipt-client-swift-*)](https://github.com/flipt-io/flipt-client-sdks/releases)
+
+The `flipt-client-swift` library contains the Swift source code for the Flipt [client-side evaluation](https://www.flipt.io/docs/integration/client) client.
+
+## Installation
+
+### Swift Package Manager
+
+Add the following to your `Package.swift` file:
+
+```swift
+dependencies: [
+ .package(url: "https://github.com/flipt-io/flipt-client-swift.git", from: "0.1.0")
+]
+```
+
+Or add it directly through Xcode:
+1. File > Add Package Dependencies
+2. Enter package URL: `https://github.com/flipt-io/flipt-client-swift`
+
+## How Does It Work?
+
+The `flipt-client-swift` library is a wrapper around the [flipt-engine-ffi](https://github.com/flipt-io/flipt-client-sdks/tree/main/flipt-engine-ffi) library.
+
+All evaluation happens within the SDK, using the shared library built from the [flipt-engine-ffi](https://github.com/flipt-io/flipt-client-sdks/tree/main/flipt-engine-ffi) library.
+
+Because the evaluation happens within the SDK, the SDKs can be used in environments where the Flipt server is not available or reachable after the initial data is fetched.
+
+## Data Fetching
+
+Upon instantiation, the `flipt-client-swift` library will fetch the flag state from the Flipt server and store it in memory. This means that the first time you use the SDK, it will make a request to the Flipt server.
+
+### Polling (Default)
+
+By default, the SDK will poll the Flipt server for new flag state at a regular interval. This interval can be configured using the `updateInterval` option when constructing a client. The default interval is 120 seconds.
+
+### Streaming (Flipt Cloud Only)
+
+[Flipt Cloud](https://flipt.io/cloud) users can use the `streaming` fetch method to stream flag state changes from the Flipt server to the SDK.
+
+When in streaming mode, the SDK will connect to the Flipt server and open a persistent connection that will remain open until the client is closed. The SDK will then receive flag state changes in real-time.
+
+## Supported Platforms
+
+This SDK currently supports the following platforms/architectures:
+
+- iOS arm64
+- iOS Simulator arm64
+- macOS arm64
+
+## Usage
+
+```swift
+import FliptClient
+
+// Initialize the client
+let client = try FliptClient(
+ namespace: "default",
+ url: "http://localhost:8080",
+ authentication: .clientToken("your-token"),
+ updateInterval: 120,
+ fetchMode: .polling
+)
+
+// Evaluate a boolean flag
+let boolResult = try client.evaluateBoolean(
+ flagKey: "my-flag",
+ entityId: "user-123",
+ context: ["key": "value"]
+)
+print("Flag enabled: \(boolResult.enabled)")
+
+// Evaluate a variant flag
+let variantResult = try client.evaluateVariant(
+ flagKey: "my-variant-flag",
+ entityId: "user-123",
+ context: ["key": "value"]
+)
+print("Variant key: \(variantResult.variantKey)")
+
+// Don't forget to close the client when you're done
+defer {
+ client.close()
+}
+```
+
+### Authentication
+
+The `FliptClient` supports the following authentication strategies:
+
+- No Authentication (default)
+- [Client Token Authentication](https://docs.flipt.io/authentication/using-tokens)
+- [JWT Authentication](https://docs.flipt.io/authentication/using-jwts)
+
+## Memory Management
+
+The engine that is allocated on the Rust side to compute evaluations for flag state will not be properly deallocated unless you call the `close()` method on a `FliptClient` instance.
+
+**Please be sure to do this to avoid leaking memory!**
+
+```swift
+defer {
+ client.close()
+}
+```
+
+## Contributing
+
+Contributions are welcome! Please feel free to open an issue or submit a Pull Request.
+
+## License
+
+This project is licensed under the [MIT License](LICENSE).
diff --git a/release/release.py b/release/release.py
index 023285e3..e009dda0 100644
--- a/release/release.py
+++ b/release/release.py
@@ -2,7 +2,7 @@
from semver import VersionInfo
from prompt_toolkit.shortcuts import checkboxlist_dialog, radiolist_dialog
from colorama import init, Fore, Style
-from sdks import GoSDK, JavaSDK, JavaScriptSDK, RubySDK, PythonSDK, DartSDK
+from sdks import GoSDK, JavaSDK, JavaScriptSDK, RubySDK, PythonSDK, DartSDK, SwiftSDK, CSharpSDK
from sdks.base import SDK, MuslSupportSDK
# Initialize colorama
@@ -19,6 +19,8 @@ def get_sdk(name: str, path: str) -> SDK:
"flipt-client-dart": DartSDK,
"flipt-client-python": PythonSDK,
"flipt-client-ruby": RubySDK,
+ "flipt-client-swift": SwiftSDK,
+ "flipt-client-csharp": CSharpSDK,
}
return sdk_classes[name](name, path)
@@ -43,6 +45,8 @@ def update_sdk_versions(bump_type="patch", sdks_to_update=None):
"flipt-client-dart",
"flipt-client-python",
"flipt-client-ruby",
+ "flipt-client-swift",
+ "flipt-client-csharp",
]
sdk_dirs = sdks_to_update if sdks_to_update else all_sdk_dirs
@@ -97,6 +101,8 @@ def get_sdk_selection(all_sdk_dirs):
"flipt-client-dart": "Dart",
"flipt-client-python": "Python",
"flipt-client-ruby": "Ruby",
+ "flipt-client-swift": "Swift",
+ "flipt-client-csharp": "C#",
}
selected_sdks = checkboxlist_dialog(
@@ -149,6 +155,8 @@ def main():
"flipt-client-dart",
"flipt-client-python",
"flipt-client-ruby",
+ "flipt-client-swift",
+ "flipt-client-csharp",
]
selected_sdks = get_sdk_selection(all_sdk_dirs)
diff --git a/release/sdks/__init__.py b/release/sdks/__init__.py
index 5357572e..440efdee 100644
--- a/release/sdks/__init__.py
+++ b/release/sdks/__init__.py
@@ -4,3 +4,5 @@
from .ruby import RubySDK
from .python import PythonSDK
from .dart import DartSDK
+from .swift import SwiftSDK
+from .csharp import CSharpSDK
diff --git a/release/sdks/csharp.py b/release/sdks/csharp.py
new file mode 100644
index 00000000..37fa33eb
--- /dev/null
+++ b/release/sdks/csharp.py
@@ -0,0 +1,32 @@
+import os
+import re
+from .base import SDK
+
+
+class CSharpSDK(SDK):
+ def get_current_version(self):
+ return self._get_version_from_file("src/FliptClient/FliptClient.csproj")
+
+ def _get_version_from_file(self, filename):
+ with open(os.path.join(self.path, filename), "r") as f:
+ content = f.read()
+ # 0.0.1
+ match = re.search(r"([\d.]+)", content)
+ if match:
+ return match.group(1)
+ raise ValueError(f"Version not found in {filename}")
+
+ def update_version(self, new_version):
+ self._update_version_in_file("src/FliptClient/FliptClient.csproj", new_version)
+
+ def _update_version_in_file(self, filename, new_version):
+ file_path = os.path.join(self.path, filename)
+ with open(file_path, "r") as f:
+ content = f.read()
+
+ updated_content = re.sub(
+ r"([\d.]+)", f"{new_version}", content
+ )
+
+ with open(file_path, "w") as f:
+ f.write(updated_content)
diff --git a/release/sdks/swift.py b/release/sdks/swift.py
new file mode 100644
index 00000000..4e56f336
--- /dev/null
+++ b/release/sdks/swift.py
@@ -0,0 +1,29 @@
+import subprocess
+from colorama import Fore, Style
+from .base import SDK
+
+
+class SwiftSDK(SDK):
+ def get_current_version(self) -> str:
+ return self._get_version_from_tag(f"{self.name}-v*")
+
+ def _get_version_from_tag(self, tag_pattern: str) -> str:
+ try:
+ result = subprocess.run(
+ ["git", "describe", "--tags", "--abbrev=0", "--match", tag_pattern],
+ capture_output=True,
+ text=True,
+ check=True,
+ )
+ latest_tag = result.stdout.strip()
+ return latest_tag.split("-v")[-1]
+ except subprocess.CalledProcessError:
+ print(
+ f"{Fore.YELLOW}Warning: No tags found for {tag_pattern}. Using 0.0.0 as the base version.{Style.RESET_ALL}"
+ )
+ return "0.0.0"
+
+ def update_version(self, new_version: str):
+ print(
+ f"{Fore.YELLOW}Note: Version for {self.name} is managed via Git tags. No files updated.{Style.RESET_ALL}"
+ )
\ No newline at end of file