Add GitHub Actions workflow to build and release Swift SDK
- Add release-sdk-swift.yml to automate building and publishing the smbCloud Auth Swift XCFramework and updating the Swift package repo - Update release-crate.yml to trigger the Swift SDK workflow when relevant crates are
Seto Elkahfi committed
May 16, 2026 at 18:43 UTC
60fd87e8357891d07d5caaba34b831a257fa2ca1
2 files changed
+445
.github/workflows/release-crate.yml
+25
@@ -28,6 +28,7 @@ jobs:
28
publish_cli_sdk_pypi: ${{ steps.downstream.outputs.publish_cli_sdk_pypi }}
29
publish_cli_sdk_npm: ${{ steps.downstream.outputs.publish_cli_sdk_npm }}
30
publish_cli_sdk_gem: ${{ steps.downstream.outputs.publish_cli_sdk_gem }}
31
+ publish_cli_sdk_swift: ${{ steps.downstream.outputs.publish_cli_sdk_swift }}
32
33
steps:
34
- name: Checkout
@@ -128,14 +129,17 @@ jobs:
129
publish_cli_sdk_pypi="$(jq -r 'map(.name) | any(. == "smbcloud-auth-sdk-py" or . == "smbcloud-auth-sdk" or . == "smbcloud-model" or . == "smbcloud-network")' plan.json)"
130
publish_cli_sdk_npm="$(jq -r 'map(.name) | any(. == "smbcloud-auth-sdk-wasm" or . == "smbcloud-auth-sdk" or . == "smbcloud-network" or . == "smbcloud-networking")' plan.json)"
131
publish_cli_sdk_gem="$(jq -r 'map(.name) | any(. == "smbcloud-auth-sdk" or . == "smbcloud-model" or . == "smbcloud-network")' plan.json)"
132
+ publish_cli_sdk_swift="$(jq -r 'map(.name) | any(. == "smbcloud-auth-sdk" or . == "smbcloud-auth-sdk-apple" or . == "smbcloud-model" or . == "smbcloud-network")' plan.json)"
133
134
echo "publish_cli_sdk_pypi=${publish_cli_sdk_pypi}" >> "$GITHUB_OUTPUT"
135
echo "publish_cli_sdk_npm=${publish_cli_sdk_npm}" >> "$GITHUB_OUTPUT"
136
echo "publish_cli_sdk_gem=${publish_cli_sdk_gem}" >> "$GITHUB_OUTPUT"
137
+ echo "publish_cli_sdk_swift=${publish_cli_sdk_swift}" >> "$GITHUB_OUTPUT"
138
139
echo "SDK PyPI trigger: ${publish_cli_sdk_pypi}"
140
echo "SDK npm trigger: ${publish_cli_sdk_npm}"
141
echo "SDK gem trigger: ${publish_cli_sdk_gem}"
142
+ echo "SDK Swift trigger: ${publish_cli_sdk_swift}"
143
144
- name: Publish workspace crates to crates.io
145
if: steps.plan.outputs.count != '0'
@@ -279,3 +283,24 @@ jobs:
283
tag: '${{ needs.publish.outputs.tag }}'
284
}
285
})
286
+
287
+ dispatch-sdk-swift:
288
+ name: Trigger SDK Swift release
289
+ needs: publish
290
+ if: needs.publish.outputs.publish_cli_sdk_swift == 'true'
291
+ runs-on: ubuntu-latest
292
+
293
+ steps:
294
+ - name: Trigger SDK Swift release workflow
295
+ uses: actions/github-script@v7
296
+ with:
297
+ script: |
298
+ await github.rest.actions.createWorkflowDispatch({
299
+ owner: context.repo.owner,
300
+ repo: context.repo.repo,
301
+ workflow_id: 'release-sdk-swift.yml',
302
+ ref: '${{ needs.publish.outputs.tag }}',
303
+ inputs: {
304
+ tag: '${{ needs.publish.outputs.tag }}'
305
+ }
306
+ })
.github/workflows/release-sdk-swift.yml
new
+420
@@ -0,0 +1,420 @@
1
+name: SDK Swift Release
2
+
3
+# Builds the Apple-platform XCFramework for the smbCloud Auth Swift package,
4
+# updates the standalone `smbcloud-auth-swift` repo, tags it with the release
5
+# version, and publishes the XCFramework zip as a GitHub Release asset.
6
+#
7
+# Required secrets:
8
+# SMBCLOUD_SWIFT_REPO_TOKEN — GitHub token/PAT with contents:write access to
9
+# smbcloudXYZ/smbcloud-auth-swift
10
+
11
+on:
12
+ workflow_dispatch:
13
+ inputs:
14
+ tag:
15
+ description: "Release tag (e.g. v0.4.1)"
16
+ required: true
17
+
18
+permissions:
19
+ contents: read
20
+
21
+env:
22
+ CARGO_TERM_COLOR: always
23
+ SWIFT_SDK_REPOSITORY: smbcloudXYZ/smbcloud-auth-swift
24
+ SWIFT_XCFRAMEWORK_NAME: smbcloud_authFFI.xcframework
25
+ SWIFT_XCFRAMEWORK_ZIP: smbcloud_authFFI.xcframework.zip
26
+
27
+jobs:
28
+ publish-sdk-swift:
29
+ name: Build and publish SmbCloudAuth Swift SDK
30
+ runs-on: macos-26
31
+
32
+ steps:
33
+ - name: Checkout smbcloud-cli
34
+ uses: actions/checkout@v6
35
+ with:
36
+ ref: ${{ github.event.inputs.tag || github.ref }}
37
+
38
+ - name: Checkout smbcloud-auth-swift
39
+ uses: actions/checkout@v6
40
+ with:
41
+ repository: ${{ env.SWIFT_SDK_REPOSITORY }}
42
+ path: swift-sdk
43
+ fetch-depth: 0
44
+ token: ${{ secrets.SMBCLOUD_SWIFT_REPO_TOKEN }}
45
+
46
+ - name: Set the release version
47
+ shell: bash
48
+ run: |
49
+ if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
50
+ release_version="${GITHUB_REF_NAME#v}"
51
+ else
52
+ release_version="${{ github.event.inputs.tag }}"
53
+ release_version="${release_version#v}"
54
+ fi
55
+
56
+ echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
57
+
58
+ - name: Prepare smbcloud-auth-swift working tree
59
+ id: swift-repo
60
+ shell: bash
61
+ working-directory: swift-sdk
62
+ run: |
63
+ set -euo pipefail
64
+
65
+ git fetch origin --tags
66
+
67
+ default_branch="$(git remote show origin | sed -n '/HEAD branch/s/.*: //p')"
68
+ if [[ -z "${default_branch}" ]]; then
69
+ echo "Failed to determine default branch for ${SWIFT_SDK_REPOSITORY}" >&2
70
+ exit 1
71
+ fi
72
+
73
+ git checkout -B "${default_branch}" "origin/${default_branch}"
74
+ echo "default_branch=${default_branch}" >> "$GITHUB_OUTPUT"
75
+
76
+ - name: Read Rust toolchain
77
+ shell: bash
78
+ run: |
79
+ rust_toolchain="$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml | head -n 1)"
80
+ if [[ -z "${rust_toolchain}" ]]; then
81
+ echo "Failed to read Rust toolchain from rust-toolchain.toml" >&2
82
+ exit 1
83
+ fi
84
+
85
+ echo "RUST_TOOLCHAIN=${rust_toolchain}" >> "$GITHUB_ENV"
86
+
87
+ - name: Install stable Rust with Apple targets
88
+ uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9
89
+ with:
90
+ toolchain: ${{ env.RUST_TOOLCHAIN }}
91
+ targets: aarch64-apple-ios,aarch64-apple-ios-sim,aarch64-apple-darwin
92
+
93
+ - name: Install nightly Rust with Apple targets
94
+ uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9
95
+ with:
96
+ toolchain: nightly
97
+ targets: aarch64-apple-tvos,aarch64-apple-tvos-sim,aarch64-apple-visionos,aarch64-apple-visionos-sim
98
+
99
+ - name: Setup Rust cache
100
+ uses: Swatinem/rust-cache@v2
101
+ with:
102
+ key: sdk-swift
103
+
104
+ - name: Verify Rust crate versions match tag
105
+ shell: bash
106
+ run: |
107
+ set -euo pipefail
108
+
109
+ cargo metadata --no-deps --format-version 1 > metadata.json
110
+
111
+ for crate_name in smbcloud-auth-sdk smbcloud-auth-sdk-apple; do
112
+ cargo_version="$(jq -r --arg crate_name "${crate_name}" '.packages[] | select(.name == $crate_name) | .version' metadata.json)"
113
+
114
+ echo "${crate_name} version : ${cargo_version}"
115
+ echo "Release tag version : ${RELEASE_VERSION}"
116
+
117
+ if [[ -z "${cargo_version}" || "${cargo_version}" == "null" ]]; then
118
+ echo "::error::Unable to find ${crate_name} in cargo metadata."
119
+ exit 1
120
+ fi
121
+
122
+ if [[ "${cargo_version}" != "${RELEASE_VERSION}" ]]; then
123
+ echo "::error::Version mismatch — ${crate_name} must be ${RELEASE_VERSION} before releasing Swift SDK."
124
+ exit 1
125
+ fi
126
+ done
127
+
128
+ - name: Build XCFramework and generated Swift bindings
129
+ id: build
130
+ shell: bash
131
+ run: |
132
+ set -euo pipefail
133
+
134
+ cli_repo="${GITHUB_WORKSPACE}"
135
+ swift_repo="${GITHUB_WORKSPACE}/swift-sdk"
136
+ build_root="${RUNNER_TEMP}/smbcloud-auth-swift-build"
137
+ generated_dir="${build_root}/generated"
138
+ headers_dir="${build_root}/Headers"
139
+ frameworks_dir="${build_root}/frameworks"
140
+ output_xcframework="${swift_repo}/${SWIFT_XCFRAMEWORK_NAME}"
141
+ output_zip="${swift_repo}/dist/${SWIFT_XCFRAMEWORK_ZIP}"
142
+ bindgen_bin="${cli_repo}/target/release/uniffi-bindgen"
143
+ apple_manifest="${cli_repo}/crates/smbcloud-auth-sdk-apple/Cargo.toml"
144
+ workspace_manifest="${cli_repo}/Cargo.toml"
145
+ static_lib_name="libsmbcloud_auth.a"
146
+
147
+ rm -rf "${build_root}" "${output_xcframework}" "${swift_repo}/dist"
148
+ mkdir -p "${generated_dir}" "${headers_dir}" "${frameworks_dir}" "${swift_repo}/dist"
149
+
150
+ cargo +"${RUST_TOOLCHAIN}" build \
151
+ --manifest-path "${apple_manifest}" \
152
+ --features bindgen \
153
+ --bin uniffi-bindgen \
154
+ --release
155
+
156
+ IPHONEOS_DEPLOYMENT_TARGET=16.0 cargo +"${RUST_TOOLCHAIN}" rustc \
157
+ --manifest-path "${workspace_manifest}" \
158
+ --package smbcloud-auth-sdk-apple \
159
+ --target aarch64-apple-ios \
160
+ --release \
161
+ --lib \
162
+ --crate-type staticlib
163
+
164
+ IPHONEOS_DEPLOYMENT_TARGET=16.0 cargo +"${RUST_TOOLCHAIN}" rustc \
165
+ --manifest-path "${workspace_manifest}" \
166
+ --package smbcloud-auth-sdk-apple \
167
+ --target aarch64-apple-ios-sim \
168
+ --release \
169
+ --lib \
170
+ --crate-type staticlib
171
+
172
+ MACOSX_DEPLOYMENT_TARGET=14.0 cargo +"${RUST_TOOLCHAIN}" rustc \
173
+ --manifest-path "${workspace_manifest}" \
174
+ --package smbcloud-auth-sdk-apple \
175
+ --target aarch64-apple-darwin \
176
+ --release \
177
+ --lib \
178
+ --crate-type staticlib
179
+
180
+ TVOS_DEPLOYMENT_TARGET=16.0 cargo +nightly rustc -Z build-std \
181
+ --manifest-path "${workspace_manifest}" \
182
+ --package smbcloud-auth-sdk-apple \
183
+ --target aarch64-apple-tvos \
184
+ --release \
185
+ --lib \
186
+ --crate-type staticlib
187
+
188
+ TVOS_DEPLOYMENT_TARGET=16.0 cargo +nightly rustc -Z build-std \
189
+ --manifest-path "${workspace_manifest}" \
190
+ --package smbcloud-auth-sdk-apple \
191
+ --target aarch64-apple-tvos-sim \
192
+ --release \
193
+ --lib \
194
+ --crate-type staticlib
195
+
196
+ XROS_DEPLOYMENT_TARGET=1.0 cargo +nightly rustc -Z build-std \
197
+ --manifest-path "${workspace_manifest}" \
198
+ --package smbcloud-auth-sdk-apple \
199
+ --target aarch64-apple-visionos \
200
+ --release \
201
+ --lib \
202
+ --crate-type staticlib
203
+
204
+ XROS_DEPLOYMENT_TARGET=1.0 cargo +nightly rustc -Z build-std \
205
+ --manifest-path "${workspace_manifest}" \
206
+ --package smbcloud-auth-sdk-apple \
207
+ --target aarch64-apple-visionos-sim \
208
+ --release \
209
+ --lib \
210
+ --crate-type staticlib
211
+
212
+ "${bindgen_bin}" generate \
213
+ --library "${cli_repo}/target/aarch64-apple-ios/release/${static_lib_name}" \
214
+ --language swift \
215
+ --out-dir "${generated_dir}"
216
+
217
+ cp "${generated_dir}/smbcloud_auth.swift" "${swift_repo}/Sources/SmbCloudAuth/smbcloud_auth.swift"
218
+ cp "${generated_dir}/smbcloud_authFFI.h" "${headers_dir}/smbcloud_authFFI.h"
219
+
220
+ stage_framework() {
221
+ lib_input="$1"
222
+ framework_output="$2"
223
+
224
+ rm -rf "${framework_output}"
225
+ mkdir -p "${framework_output}/Headers" "${framework_output}/Modules"
226
+
227
+ cp "${lib_input}" "${framework_output}/smbcloud_authFFI"
228
+ cp "${headers_dir}/smbcloud_authFFI.h" "${framework_output}/Headers/smbcloud_authFFI.h"
229
+
230
+ cat > "${framework_output}/Modules/module.modulemap" <<'EOF'
231
+ framework module smbcloud_authFFI {
232
+ header "smbcloud_authFFI.h"
233
+ export *
234
+ use "Darwin"
235
+ use "_Builtin_stdbool"
236
+ use "_Builtin_stdint"
237
+ }
238
+ EOF
239
+
240
+ cat > "${framework_output}/Info.plist" <<EOF
241
+ <?xml version="1.0" encoding="UTF-8"?>
242
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
243
+ <plist version="1.0">
244
+ <dict>
245
+ <key>CFBundleIdentifier</key>
246
+ <string>xyz.smbcloud.smbcloud-auth-ffi</string>
247
+ <key>CFBundleName</key>
248
+ <string>smbcloud_authFFI</string>
249
+ <key>CFBundleExecutable</key>
250
+ <string>smbcloud_authFFI</string>
251
+ <key>CFBundlePackageType</key>
252
+ <string>FMWK</string>
253
+ <key>CFBundleShortVersionString</key>
254
+ <string>${RELEASE_VERSION}</string>
255
+ <key>CFBundleVersion</key>
256
+ <string>1</string>
257
+ </dict>
258
+ </plist>
259
+ EOF
260
+ }
261
+
262
+ stage_framework \
263
+ "${cli_repo}/target/aarch64-apple-ios/release/${static_lib_name}" \
264
+ "${frameworks_dir}/ios/smbcloud_authFFI.framework"
265
+ stage_framework \
266
+ "${cli_repo}/target/aarch64-apple-ios-sim/release/${static_lib_name}" \
267
+ "${frameworks_dir}/ios-sim/smbcloud_authFFI.framework"
268
+ stage_framework \
269
+ "${cli_repo}/target/aarch64-apple-darwin/release/${static_lib_name}" \
270
+ "${frameworks_dir}/macos/smbcloud_authFFI.framework"
271
+ stage_framework \
272
+ "${cli_repo}/target/aarch64-apple-tvos/release/${static_lib_name}" \
273
+ "${frameworks_dir}/tvos/smbcloud_authFFI.framework"
274
+ stage_framework \
275
+ "${cli_repo}/target/aarch64-apple-tvos-sim/release/${static_lib_name}" \
276
+ "${frameworks_dir}/tvos-sim/smbcloud_authFFI.framework"
277
+ stage_framework \
278
+ "${cli_repo}/target/aarch64-apple-visionos/release/${static_lib_name}" \
279
+ "${frameworks_dir}/visionos/smbcloud_authFFI.framework"
280
+ stage_framework \
281
+ "${cli_repo}/target/aarch64-apple-visionos-sim/release/${static_lib_name}" \
282
+ "${frameworks_dir}/visionos-sim/smbcloud_authFFI.framework"
283
+
284
+ xcodebuild -create-xcframework \
285
+ -framework "${frameworks_dir}/ios/smbcloud_authFFI.framework" \
286
+ -framework "${frameworks_dir}/ios-sim/smbcloud_authFFI.framework" \
287
+ -framework "${frameworks_dir}/macos/smbcloud_authFFI.framework" \
288
+ -framework "${frameworks_dir}/tvos/smbcloud_authFFI.framework" \
289
+ -framework "${frameworks_dir}/tvos-sim/smbcloud_authFFI.framework" \
290
+ -framework "${frameworks_dir}/visionos/smbcloud_authFFI.framework" \
291
+ -framework "${frameworks_dir}/visionos-sim/smbcloud_authFFI.framework" \
292
+ -output "${output_xcframework}"
293
+
294
+ ditto -c -k --sequesterRsrc --keepParent \
295
+ "${output_xcframework}" \
296
+ "${output_zip}"
297
+
298
+ framework_checksum="$(cd "${swift_repo}" && swift package compute-checksum "dist/${SWIFT_XCFRAMEWORK_ZIP}")"
299
+
300
+ echo "FRAMEWORK_CHECKSUM=${framework_checksum}" >> "$GITHUB_ENV"
301
+ echo "framework_zip=${output_zip}" >> "$GITHUB_OUTPUT"
302
+
303
+ - name: Upload XCFramework zip artifact
304
+ uses: actions/upload-artifact@v7
305
+ with:
306
+ name: sdk-swift-xcframework
307
+ path: ${{ steps.build.outputs.framework_zip }}
308
+
309
+ - name: Update smbcloud-auth-swift package metadata
310
+ shell: bash
311
+ working-directory: swift-sdk
312
+ run: |
313
+ set -euo pipefail
314
+
315
+ python3 <<'PY'
316
+ from pathlib import Path
317
+ import os
318
+ import re
319
+
320
+ package_path = Path("Package.swift")
321
+ text = package_path.read_text()
322
+ release_version = os.environ["RELEASE_VERSION"]
323
+ checksum = os.environ["FRAMEWORK_CHECKSUM"]
324
+ url = f"https://github.com/smbcloudXYZ/smbcloud-auth-swift/releases/download/{release_version}/smbcloud_authFFI.xcframework.zip"
325
+
326
+ text = re.sub(
327
+ r'https://github\.com/smbcloudXYZ/smbcloud-auth-swift/releases/download/[^"]+/smbcloud_authFFI\.xcframework\.zip',
328
+ url,
329
+ text,
330
+ )
331
+ text = re.sub(
332
+ r'let releaseFrameworkChecksum =\n\s+"[0-9a-f]{64}"',
333
+ f'let releaseFrameworkChecksum =\n "{checksum}"',
334
+ text,
335
+ )
336
+
337
+ package_path.write_text(text)
338
+ PY
339
+
340
+ - name: Commit and tag smbcloud-auth-swift release
341
+ shell: bash
342
+ working-directory: swift-sdk
343
+ run: |
344
+ set -euo pipefail
345
+
346
+ git fetch origin --tags
347
+
348
+ if git ls-remote --tags origin "refs/tags/${RELEASE_VERSION}" | grep -q .; then
349
+ echo "::error::${SWIFT_SDK_REPOSITORY} tag ${RELEASE_VERSION} already exists."
350
+ exit 1
351
+ fi
352
+
353
+ git config user.name "github-actions[bot]"
354
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
355
+
356
+ git add Package.swift Sources/SmbCloudAuth/smbcloud_auth.swift
357
+
358
+ if ! git diff --cached --quiet; then
359
+ git commit -m "Release ${RELEASE_VERSION}"
360
+ git push origin HEAD:${{ steps.swift-repo.outputs.default_branch }}
361
+ else
362
+ echo "Swift repo metadata already up to date on ${RELEASE_VERSION}."
363
+ fi
364
+
365
+ git tag "${RELEASE_VERSION}"
366
+ git push origin "${RELEASE_VERSION}"
367
+
368
+ - name: Create GitHub Release in smbcloud-auth-swift
369
+ shell: bash
370
+ working-directory: swift-sdk
371
+ env:
372
+ GH_TOKEN: ${{ secrets.SMBCLOUD_SWIFT_REPO_TOKEN }}
373
+ run: |
374
+ set -euo pipefail
375
+
376
+ release_notes_file="${RUNNER_TEMP}/smbcloud-auth-swift-release-notes.md"
377
+ cat > "${release_notes_file}" <<EOF
378
+ ## smbCloud Auth Swift ${RELEASE_VERSION}
379
+
380
+ ### Installation
381
+
382
+ Add the Swift package dependency:
383
+
384
+ \`\`\`swift
385
+ .package(url: "https://github.com/smbcloudXYZ/smbcloud-auth-swift", from: "${RELEASE_VERSION}")
386
+ \`\`\`
387
+
388
+ ### Platforms
389
+
390
+ | Platform | Minimum Version |
391
+ |----------|-----------------|
392
+ | iOS | 16.0 |
393
+ | macOS | 14.0 |
394
+ | tvOS | 16.0 |
395
+ | visionOS | 1.0 |
396
+ EOF
397
+
398
+ if gh release view "${RELEASE_VERSION}" --repo "${SWIFT_SDK_REPOSITORY}" >/dev/null 2>&1; then
399
+ gh release upload "${RELEASE_VERSION}" "dist/${SWIFT_XCFRAMEWORK_ZIP}" \
400
+ --clobber \
401
+ --repo "${SWIFT_SDK_REPOSITORY}"
402
+ else
403
+ gh release create "${RELEASE_VERSION}" "dist/${SWIFT_XCFRAMEWORK_ZIP}" \
404
+ --repo "${SWIFT_SDK_REPOSITORY}" \
405
+ --title "smbCloud Auth Swift ${RELEASE_VERSION}" \
406
+ --notes-file "${release_notes_file}"
407
+ fi
408
+
409
+ - name: Publish summary
410
+ shell: bash
411
+ run: |
412
+ cat <<EOF >> "$GITHUB_STEP_SUMMARY"
413
+ ## Swift SDK Release
414
+
415
+ - Source tag: ${GITHUB_REF_NAME:-${{ github.event.inputs.tag }}}
416
+ - Swift repo: ${SWIFT_SDK_REPOSITORY}
417
+ - Swift tag: ${RELEASE_VERSION}
418
+ - XCFramework: ${SWIFT_XCFRAMEWORK_NAME}
419
+ - Checksum: ${FRAMEWORK_CHECKSUM}
420
+ EOF