{"id":13465338,"url":"https://github.com/swiftkube/client","last_synced_at":"2026-04-02T18:27:35.196Z","repository":{"id":37987988,"uuid":"304125670","full_name":"swiftkube/client","owner":"swiftkube","description":"Swift client for Kubernetes","archived":false,"fork":false,"pushed_at":"2024-07-01T19:49:38.000Z","size":422,"stargazers_count":126,"open_issues_count":5,"forks_count":20,"subscribers_count":9,"default_branch":"main","last_synced_at":"2024-10-02T06:46:36.214Z","etag":null,"topics":["kubernetes","kubernetes-client","server-side-swift","swift","swiftkube"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/swiftkube.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-10-14T20:17:08.000Z","updated_at":"2024-09-19T14:25:55.000Z","dependencies_parsed_at":"2024-01-08T10:17:11.163Z","dependency_job_id":"c545381f-3a17-4fe0-a20f-2185bd6da55e","html_url":"https://github.com/swiftkube/client","commit_stats":{"total_commits":187,"total_committers":7,"mean_commits":"26.714285714285715","dds":0.04278074866310155,"last_synced_commit":"c81dd0ff480885a2fd99b602dd6814e1fb423b44"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swiftkube%2Fclient","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swiftkube%2Fclient/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swiftkube%2Fclient/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/swiftkube%2Fclient/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/swiftkube","download_url":"https://codeload.github.com/swiftkube/client/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222088539,"owners_count":16928976,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["kubernetes","kubernetes-client","server-side-swift","swift","swiftkube"],"created_at":"2024-07-31T15:00:27.799Z","updated_at":"2026-04-02T18:27:35.165Z","avatar_url":"https://github.com/swiftkube.png","language":"Swift","funding_links":[],"categories":["Libs","API [🔝](#readme)","Networking"],"sub_categories":["API"],"readme":"\u003cp align=\"center\"\u003e\n\t\u003cimg src=\"./SwiftkubeClient.png\"\u003e\n\u003c/p\u003e\n\n\u003cp style=\"text-align: center;\"\u003e\n\t\u003ca href=\"https://swiftpackageindex.com/swiftkube/client\"\u003e\n      \u003cimg src=\"https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fswiftkube%2Fclient%2Fbadge%3Ftype%3Dswift-versions\"/\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://swiftpackageindex.com/swiftkube/client\"\u003e\n      \u003cimg src=\"https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fswiftkube%2Fclient%2Fbadge%3Ftype%3Dplatforms\"/\u003e\n    \u003c/a\u003e\n\t\u003ca href=\"https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.33/\"\u003e\n\t\t\u003cimg src=\"https://img.shields.io/badge/Kubernetes-1.34.6-blue.svg\" alt=\"Kubernetes 1.34.6\"/\u003e\n\t\u003c/a\u003e\n\t\u003ca href=\"https://swift.org/package-manager\"\u003e\n\t\t\u003cimg src=\"https://img.shields.io/badge/SwiftPM-compatible-brightgreen.svg?style=flat\" alt=\"Swift Package Manager\" /\u003e\n\t\u003c/a\u003e\n\t\u003ca href=\"https://github.com/swiftkube/client/actions\"\u003e\n\t\t\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/swiftkube/client/ci.yml?style=flat\" alt=\"CI Status\"\u003e\n\t\u003c/a\u003e\n\u003c/p\u003e\n\n## Table of contents\n\n* [Overview](#overview)\n* [Compatibility Matrix](#compatibility-matrix)\n* [Examples](#examples)\n* [Usage](#usage)\n  * [Creating a client](#creating-a-client)\n  * [Configuring a client](#configuring-the-client)\n  * [Client authentication](#client-authentication)\n  * [Client DSL](#client-dsl)\n  * [Loading from external sources](#loading-from-external-sources)\n  * [Type-erased usage](#type-erased-usage)\n  * [CRD Support](#crd-support)\n* [Metrics](#metrics)\n* [Installation](#installation)\n* [License](#license)\n\n## Overview\n\nSwift client for talking to a [Kubernetes](http://kubernetes.io/) cluster via a fluent DSL based \non [SwiftNIO](https://github.com/apple/swift-nio) and the [AysncHTTPClient](https://github.com/swift-server/async-http-client).\n\n- [x] Covers all Kubernetes API Groups in v1.34.6\n- [x] Automatic configuration discovery\n- [x] DSL style API\n  - [x] For all API Groups/Versions\n- [x] Generic client support\n- [x] Swift-Logging support\n- [x] Loading resources from external sources\n  - [x] from files\n  - [x] from URLs\n- [x] Read Options\n- [x] List Options\n- [x] Delete Options\n- [ ] PATCH API\n- [x] `/scale` API\n- [x] `/status` API\n- [x] Resource watch support\n- [x] Follow pod logs support\n- [x] Discovery API\n- [x] CRD support\n- [ ] Controller/Informer support\n- [x] Swift Metrics\n- [ ] Complete documentation\n- [ ] End-to-end tests\n\n## Compatibility Matrix\n\n|                   | 1.28.0 | 1.28.3 | 1.29.6 | 1.32.0 | 1.32.2 | 1.33.3 | 1.34.6 |\n|-------------------|--------|--------|--------|--------|--------|--------|--------|\n| `0.16.x`          | ✓      | -      | -      | -      | -      | -      | -      |\n| `0.17.x`          | -      | ✓      | -      | -      | -      | -      | -      |\n| `0.18.x`          | -      | -      | ✓      | -      | -      | -      | -      |\n| `0.19.x`-`0.23.0` | -      | -      | -      | ✓      | -      | -      | -      |\n| `0.24.0`          | -      | -      | -      | -      | ✓      | -      | -      |\n| `0.25.0`          | -      | -      | -      | -      | -      | ✓      | -      |\n| `0.26.0`          | -      | -      | -      | -      | -      | -      | ✓      |\n\n- `✓` Exact match of API objects in both client and the Kubernetes version.\n- `-` API objects mismatches either due to the removal of old API or the addition of new API. However, everything the \n- client and Kubernetes have in common will work.\n\n## Examples\n\nConcrete examples for using the `Swiftkube` tooling reside in the [Swiftkube:Examples](https://github.com/swiftkube/examples) \nrepository.\n\n## Usage\n\n### Creating a client\n\nTo create a client just import `SwiftkubeClient` and init an instance.\n\n ```swift\n import SwiftkubeClient\n \n let client = try KubernetesClient()\n ```\n\nYou should shut down the `KubernetesClient` instance when you're done using it, which in turn shuts down the underlying\n`HTTPClient`. Thus, you shouldn't call `client.shutdown()` before all requests have finished. You can also shut down\nthe client asynchronously in an async/await context or by providing a `DispatchQueue` for the completion callback.\n\n```swift\n// when finished close the client\ntry client.syncShutdown()\n \n// async/await\ntry await client.shutdown()\n\n// DispatchQueue\nlet queue: DispatchQueue = ...\nclient.shutdown(queue: queue) { (error: Error?) in \n    print(error)\n}\n```\n\n### Configuring the client\n\nThe client tries to resolve a `kube config` automatically from different sources in the following order:\n\n- Kube config file at path of environment variable `KUBECONFIG`, if defined\n- Kube config file in the user's `$HOME/.kube/config` directory \n- `ServiceAccount` token located at `/var/run/secrets/kubernetes.io/serviceaccount/token` and a mounted CA certificate, if it's running in Kubernetes.\n\nHowever, `KubeConfig` can also be loaded manually:\n\n```swift\nlet kubeConfig = try KubeConfig.from(config: \"\u003cconfig as a YAML string\u003e\")\nlet kubeConfig = try KubeConfig.from(url: \"\u003csome URL\u003e\")\nlet kubeConfig = try KubeConfig.fromEnvironment(envVar: \"KUBECONFIG\")\nlet kubeConfig = try KubeConfig.fromDefaultLocalConfig()\nlet kubeConfig = try KubeConfig.fromServiceAccount()\n```\n\nand then used to initialize the `KubernetesClientConfig` like this:\n\n```swift\nlet kubeConfig = KubeConfig.fromDefaultLocalConfig()\nlet config = KubernetesClientConfig.from(\n  kubeConfig: kubeConfig,\n  contextName: \"some-context\" // if not provided, then \"current-context\" is used\n)\n```\n\nAlternatively, the `KubernetesClientConfig` can be configured completely manually, for example:\n\n```swift\nlet caCert = try NIOSSLCertificate.fromPEMFile(caFile)\nlet authentication = KubernetesClientAuthentication.basicAuth(\n  username: \"admin\", \n  password: \"admin\"\n)\n\nlet config = KubernetesClientConfig(\n   masterURL: \"https://kubernetesmaster\",\n   namespace: \"default\",\n   authentication: authentication,\n   trustRoots: NIOSSLTrustRoots.certificates(caCert),\n   insecureSkipTLSVerify: false,\n   timeout: HTTPClient.Configuration.Timeout.init(connect: .seconds(1), read: .seconds(10)),\n   redirectConfiguration: HTTPClient.Configuration.RedirectConfiguration.follow(max: 5, allowCycles: false)\n)\n\nlet client = KubernetesClient(config: config)\n```\n\n### Client authentication\n\nThe following authentication schemes are supported:\n\n- Basic Auth: `.basicAuth(username: String, password: String)`\n- Bearer Token: `.bearer(token: String)`\n- Client certificate: `.x509(clientCertificate: NIOSSLCertificate, clientKey: NIOSSLPrivateKey)`\n\n### Client DSL\n\n`SwiftkubeClient` defines convenience API to work with Kubernetes resources. Using this DSL is the same for all resources.\n\nThe client exposes asynchronous functions using the new Swift concurrency model.\n\n#### List resources \n\n```swift\nlet namespaces = try await client.namespaces.list()\nlet deployments = try await client.appsV1.deployments.list(in: .allNamespaces)\nlet roles = try await client.rbacV1.roles.list(in: .namespace(\"ns\"))\n```\n\nYou can filter the listed resources or limit the returned list size via the `ListOptions`:\n\n```swift\nlet deployments = try await client.appsV1.deployments.list(in: .allNamespaces, options: [\n  .labelSelector(.eq([\"app\": \"nginx\"])),\n  .labelSelector(.notIn([\"env\": [\"dev\", \"staging\"]])),\n  .labelSelector(.exists([\"app\", \"env\"])),\n  .fieldSelector(.eq([\"status.phase\": \"Running\"])),\n  .resourceVersion(\"9001\"),\n  .limit(20),\n  .timeoutSeconds(10)\n])\n```\n\n#### Get a resource \n\n```swift\nlet namespace = try await client.namespaces.get(name: \"ns\")\nlet deployment = try await client.appsV1.deployments.get(in: .namespace(\"ns\"), name: \"nginx\")\nlet roles = try await client.rbacV1.roles.get(in: .namespace(\"ns\"), name: \"role\")\n```\n\nYou can also provide the following `ReadOptions`:\n\n```swift\nlet deployments = try await client.appsV1.deployments.get(in: .allNamespaces, options: [\n  .pretty(true),\n  .exact(false),\n  .export(true)\n])\n```\n\n#### Delete a resource\n\n```swift\ntry await client.namespaces.delete(name: \"ns\")\ntry await client.appsV1.deployments.delete(in: .namespace(\"ns\"), name: \"nginx\")\ntry await client.rbacV1.roles.delete(in: .namespace(\"ns\"), name: \"role\")\n```\n\nYou can pass an instance of `meta.v1.DeleteOptions` to control the behaviour of the delete operation:\n\n```swift\nlet deletOptions = meta.v1.DeleteOptions(\n  gracePeriodSeconds: 10,\n  propagationPolicy: \"Foreground\"\n)\ntry await client.pods.delete(in: .namespace(\"ns\"), name: \"nginx\", options: deleteOptions)\n```\n\n#### Create and update a resource\n\nResources can be created/updated directly or via the convenience builders defined in [SwiftkubeModel](https://github.com/swiftkube/model)\n\n```swift\n// Create a resource instance and post it\nlet configMap = core.v1.ConfigMap(\n  metadata: meta.v1.ObjectMeta(name: \"test\"),\n  data: [\"foo\": \"bar\"]\n)\ntry cm = try await client.configMaps.create(inNamespace: .default, configMap)\n\n// Or inline via a builder\nlet pod = try await client.pods.create(inNamespace: .default) {\n   sk.pod {\n     $0.metadata = sk.metadata(name: \"nginx\")\n     $0.spec = sk.podSpec {\n       $0.containers = [\n         sk.container(name: \"nginx\") {\n           $0.image = \"nginx\"\n         }\n       ]\n     }\n   }\n}\n```\n\n#### Watch a resource\n\nYou can watch for Kubernetes events about specific objects via the `watch` API.  \n\nWatching resources opens a persistent connection to the API server. The connection is represented by a `SwiftkubeClientTask` \ninstance, that acts as an active \"subscription\" to the events stream.\n\nThe task instance must be started explicitly via ``SwiftkubeClientTask/start()``, which returns an \n``AsyncThrowingStream``, that starts yielding items immediately as they are received from the Kubernetes API server.\n\n\u003e The async stream buffers its results if there are no active consumers. The ``AsyncThrowingStream.BufferingPolicy.unbounded``\nbuffering policy is used, which should be taken into consideration.\n\n```swift\nlet task: SwiftkubeClientTask = try await client.pods.watch(in: .allNamespaces)\nlet stream = await task.start()\n\nfor try await event in stream {\n  print(event)\n}\n```\n\nYou can also pass `ListOptions` to filter, i.e. select the required objects:\n\n```swift\nlet options = [\n  .labelSelector(.eq([\"app\": \"nginx\"])),\n  .labelSelector(.exists([\"env\"]))\n]\n\nlet task = try await client.pods.watch(in: .default, options: options)\n```\n\nThe client reconnects automatically and restarts the watch upon encountering non-recoverable errors. The \nreconnect-behaviour can be controlled by passing an instance of `RetryStrategy`.\n\nThe default strategy is 10 retry attempts with a fixed 5 seconds delay between each attempt. The initial delay is one\nsecond. A jitter of 0.2 seconds is applied.\n\nPassing `RetryStrategy.never` disables any reconnection attempts.\n\n```swift\nlet strategy = RetryStrategy(\n  policy: .maxAttemtps(20),\n  backoff: .exponentiaBackoff(maxDelay: 60, multiplier: 2.0),\n  initialDelay = 5.0,\n  jitter = 0.2\n)\nlet task = try await client.pods.watch(in: .default, retryStrategy: strategy)\n\nfor try await event in await task.stream() {\n  print(event)\n}\n```\n\nThe task must be cancelled when it is no longer needed:\n\n```swift\ntask.cancel()\n```\n\n#### Follow logs\n\nThe `follow` API resembles the `watch`, but instead of events, it emits the log lines.\n\n:warning: The client does not reconnect on errors in `follow` mode.\n\n```swift\nlet task = try await client.pods.follow(in: .default, name: \"nginx\", container: \"app\")\n\nfor try await line in await task.start() {\n  print(line)\n}\n\n// The task can be cancelled later to stop following logs\ntask.cancel()\n```\n\n### Discovery\n\nThe client provides a discovery interface for the API server, which can be used to retrieve the server version, the API \ngroups and the API resources for a specific group version.\n\n```swift\nlet version: Info = try await client.discovery.serverVersion()\nlet groups: meta.v1.APIGroupList = try await client.discovery.serverGroups()\nlet resources: meta.v1.APIResourceList = try await client.discovery.serverResources(forGroupVersion: \"apps/v1\")\n```\n\n### Loading from external sources\n\nA resource can be loaded from a file or a URL:\n\n```swift\n// Load from URL, e.g. a file\nlet url = URL(fileURLWithPath: \"/path/to/manifest.yaml\")\nlet deployment = try apps.v1.Deployment.load(contentsOf: url)\n```\n\n### Type-erased usage\n\nOften when working with Kubernetes the concrete type of the resource is not known or not relevant, e.g. when creating \nresources from a YAML manifest file. Other times the type or kind of the resource must be derived at runtime given its \nstring representation.\n\nLeveraging `SwiftkubeModel`'s type-erased resource implementations `UnstructuredResource` and its corresponding \nList-Type `UnstructuredResourceList` it is possible to have a generic client instance, which must be initialized\nwith a `GroupVersionResource` type:\n\n```swift\nguard let gvr = try? GroupVersionResource(for: \"deployment\") else {\n   // handle this\n}\n\n// Get by name\nlet resource: UnstructuredResource = try await client.for(gvr: gvr).get(in: .default , name: \"nginx\")\n\n// List all\nlet resources: UnstructuredResourceList = try await client.for(gvr: gvr).list(in: .allNamespaces)\n```\n\n#### GroupVersionKind \u0026 GroupVersionResource\n\nA `GroupVersionKind` \u0026 `GroupVersionResource` can be initialized from:\n\n- `KubernetesAPIResource` instance\n- `KubernetesAPIResource` type\n- Full API Group string\n- Lower-cased singular resource kind\n- Lower-cased plural resource name\n- Lower-cased short resource name\n\n```swift\nlet deployment = ..\nlet gvk = GroupVersionKind(of: deployment)\nlet gvr = GroupVersionResource(of: deployment)\nlet gvk = GroupVersionKind(of: apps.v1.Deployment.self)\nlet gvr = GroupVersionResource(for: \"configmaps\")\nlet gvk = GroupVersionKind(for: \"cm\")\nlet gvr = GroupVersionResource(for: \"cm\")\n// etc.\n```\n\n### CRD Support\n\n`SwiftkubeClient` supports Custom Resource Definitions (CRDs) natively. For example, a CRD manifest can be loaded\nfrom a YAML file or created programmatically, and then created via the client DSL:\n\n```swift\nlet crd = apiextensions.v1.CustomResourceDefinition.load(contentsOf: URL(filePath: \"/path/to/crd.yaml\"))\ntry await client.apiExtensionsV1.customResourceDefinitions.create(crd)\n```\n\nThe `KubernetesClient` can now be \"extended\", in order to manage the Custom Resources. One way would be to use the\n`UnstructuredResource` described in the previous section given some `GroupVersionResource`.\n\nHowever, the client can work with any object that implements the relevant marker protocols, which allows for custom types\nto be defined and used directly.\n\nHere is a complete example to clarify.\n\nGiven the following CRD:\n\n```yaml\napiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\nmetadata:\n  name: crontabs.example.com\nspec:\n  group: example.com\n  names:\n    plural: crontabs\n    singular: crontab\n    kind: CronTab\n    shortNames:\n      - ct\n  scope: Namespaced\n  versions:\n    - name: v1\n      served: true\n      storage: true\n      schema:\n        openAPIV3Schema:\n          type: object\n          properties:\n            spec:\n              type: object\n              properties:\n                cronSpec:\n                  type: string\n                image:\n                  type: string\n                replicas:\n                  type: integer\n```\n\nThe marker protocols are:\n\n- `KubernetesAPIResource` marks the object as a Kubernetes resource that has a corresponding API endpoint\n- `NamespacedResource` \u0026 `ClusterScopedResource` to indicate whether the resource is namespaced or cluster-scoped\n- `ReadableResource` activates the `get`, `list` and `watch` API for the resource\n- `CreatableResource` activates the `create` API for the resource\n- `ReplaceableResource` activates the `update` API for the resource\n- `DeletableResource` activates the `delete` API for the resource\n- `CollectionDeletableResource` activate the `deleteAll` API for the resource\n- `ScalableResource` activates the `scale` API for the resource\n- `MetadataHavingResource` indicates, that the resource has a `metadata` field of type `meta.v1.ObjectMeta?`\n- `StatusHavingResource` indicate, that the resource has a `state` field (w/o assuming its type)\n\nThe following custom structs can be defined:\n\n```swift\nstruct CronTab: KubernetesAPIResource, NamespacedResource, MetadataHavingResource, \n        ReadableResource, CreatableResource, ListableResource {\n  typealias List = CronTabList\n  var apiVersion = \"example.com/v1\"\n  var kind = \"CronTab\"\n  var metadata: meta.v1.ObjectMeta?\n  var spec: CronTabSpec\n}\n\nstruct CronTabSpec: Codable, Hashable, Sendable {\n  var cronSpec: String\n  var image: String\n  var replicas: Int\n}\n\nstruct CronTabList: KubernetesResourceList {\n  var apiVersion = \"example.com/v1\"\n  var kind = \"crontabs\"\n  var items: [CronTab]\n}\n```\n\nNow, the new Custom Resource can be used like any other Kubernetes resource:\n\n```swift\nlet gvr = GroupVersionResource(\n  group: \"example.com\",\n  version: \"v1\",\n  resource: \"crontabs\"\n)\n\nlet cronTabClient = client.for(CronTab.self, gvr: gvr)\n\nlet cronTab = CronTab(\n  metadata: meta.v1.ObjectMeta(name: \"new-cron\"),\n  spec: CronTabSpec(\n    cronSpec : \"* * * * */5\",\n    image: \"some-cron-image\",\n    replicas: 2\n  )\n)\n\nlet new = try await cronTabClient.create(in: .default, cronTab)\nlet cronTabs: CronTabList = try await cronTabClient.list(in: .allNamespaces)\n```\n\n## Metrics\n\n`KubernetesClient` uses [SwiftMetrics](https://github.com/apple/swift-metrics) to collect metric information about the \nrequests count and latencies.\n\nThe following metrics are gathered:\n\n- `sk_http_requests_total(counter)`: the total count of the requests made by the client.\n- `sk_http_request_errors_total(counter)`: the total number of requests made, that returned a http error.\n- `sk_request_errors_total(counter)`: the total number of requests that couldn't be dispatched due to non-http errors.\n- `sk_http_request_duration_seconds(timer)`: the complete request durations.\n\n### Collecting the metrics\n\nTo collect the metrics you have to bootstrap a metrics backend in your application. For example, you can collect the \nmetrics to prometheus via `SwiftPrometheus`:\n\n```swift\nimport Metrics\nimport Prometheus\n\nlet prom = PrometheusClient()\nMetricsSystem.bootstrap(prom)\n```\n\nand expose a `/metrics` endpoint for scraping:\n\n```swift\n// if using vapor\napp.get(\"metrics\") { request -\u003e EventLoopFuture\u003cString\u003e in\n    let promise = request.eventLoop.makePromise(of: String.self)\n    try MetricsSystem.prometheus().collect(into: promise)\n    return promise.futureResult\n}\n```\n\n## Installation\n\nTo use the `SwiftkubeClient` in a SwiftPM project, add the following line to the dependencies in your `Package.swift` file:\n\n```swift\n.package(name: \"SwiftkubeClient\", url: \"https://github.com/swiftkube/client.git\", from: \"0.23.0\")\n```\n\nthen include it as a dependency in your target:\n\n```swift\nimport PackageDescription\n\nlet package = Package(\n    // ...\n    dependencies: [\n        .package(name: \"SwiftkubeClient\", url: \"https://github.com/swiftkube/client.git\", from: \"0.23.0\")\n    ],\n    targets: [\n        .target(name: \"\u003cyour-target\u003e\", dependencies: [\n            .product(name: \"SwiftkubeClient\", package: \"SwiftkubeClient\"),\n        ])\n    ]\n)\n```\n\nThen run `swift build`.\n\n## License\n\nSwiftkube project is licensed under version 2.0 of the [Apache License](https://www.apache.org/licenses/LICENSE-2.0). See [LICENSE](./LICENSE) for more details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswiftkube%2Fclient","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fswiftkube%2Fclient","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fswiftkube%2Fclient/lists"}