@smbcloud / cli / commits / 60fd87e

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