Publish the smbcloud-model gem from the SDK release workflow
The release workflow only built sdk/gems/auth, so smbcloud-model 0.7.x never reached RubyGems and the latest published version is still 0.3.31. Build and push both gems, checking RubyGems per gem so a re-run skips the one that is already published. Add an optional ref input so a release can be built from a commit newer than its tag. The model Rakefile also lacked the install_name_tool step that the auth gem uses. Without it, macOS 15+ rejects the bundle because its LC_ID_DYLIB is empty. Copy the same fix over. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Seto Elkahfi committed
Oct 24, 2026 at 11:07 UTC
47b5c8e82de4932f2477136b3e5ec3782d319e15
2 files changed
+57
-25
.github/workflows/release-sdk-gem.yml
+39
-25
@@ -1,18 +1,23 @@
1
name: SDK Ruby Gem Release
2
3
-# Publishes the smbcloud-auth Ruby gem (sdk/gems/auth) to RubyGems.
3
+# Publishes the smbcloud-auth (sdk/gems/auth) and smbcloud-model
4
+# (sdk/gems/model) Ruby gems to RubyGems.
5
# Builds pre-compiled native gems for the supported Unix platforms, plus a
6
# source gem as a fallback for unsupported environments.
7
#
8
# Required secrets:
8
-# RUBYGEMS_API_KEY — RubyGems.org API key with push access to smbcloud-auth
9
+# RUBYGEMS_API_KEY — RubyGems.org API key with push access to smbcloud-auth and
10
+# smbcloud-model
11
12
on:
13
workflow_dispatch:
14
inputs:
15
tag:
14
- description: "Release tag (e.g. v0.3.35)"
16
+ description: "Release version (e.g. v0.3.35)"
17
required: true
18
+ ref:
19
+ description: "Git ref to build from (defaults to the tag)"
20
+ required: false
21
22
permissions:
23
contents: read
@@ -23,11 +28,12 @@ env:
28
jobs:
29
# ── Build native gems ──────────────────────────────────────────────────────
30
build-gems:
26
- name: Build gem (${{ matrix.name }})
31
+ name: Build ${{ matrix.gem }} gem (${{ matrix.name }})
32
runs-on: ${{ matrix.runner }}
33
strategy:
34
fail-fast: false
35
matrix:
36
+ gem: [auth, model]
37
include:
38
- { name: linux-x64, runner: ubuntu-latest, platform: x86_64-linux }
39
- {
@@ -50,7 +56,7 @@ jobs:
56
- name: Checkout
57
uses: actions/checkout@v6
58
with:
53
- ref: ${{ github.event.inputs.tag || github.ref }}
59
+ ref: ${{ inputs.ref || inputs.tag || github.ref }}
60
61
- name: Set the release version
62
shell: bash
@@ -104,43 +110,47 @@ jobs:
110
111
- name: Resolve the published Rust crate dependencies
112
shell: bash
107
- run: cargo generate-lockfile --manifest-path sdk/gems/auth/Cargo.toml
113
+ run: cargo generate-lockfile --manifest-path sdk/gems/${{ matrix.gem }}/Cargo.toml
114
115
# Scope the Rust cache to the gem's own Cargo workspace so its registry
116
# deps are cached independently from the main workspace.
117
- name: Setup Rust cache
118
uses: Swatinem/rust-cache@v2
119
with:
114
- key: sdk-gem-${{ matrix.name }}
115
- workspaces: sdk/gems/auth
120
+ key: sdk-gem-${{ matrix.gem }}-${{ matrix.name }}
121
+ workspaces: sdk/gems/${{ matrix.gem }}
122
123
- name: Setup Ruby
124
uses: ruby/setup-ruby@v1
125
with:
126
ruby-version: .ruby-version
127
bundler-cache: true
122
- working-directory: sdk/gems/auth
128
+ working-directory: sdk/gems/${{ matrix.gem }}
129
130
- name: Build native gem
125
- working-directory: sdk/gems/auth
131
+ working-directory: sdk/gems/${{ matrix.gem }}
132
shell: bash
133
run: bundle exec rake native gem
134
135
- name: Upload gem artifact
136
uses: actions/upload-artifact@v7
137
with:
132
- name: gem-${{ matrix.name }}
133
- path: sdk/gems/auth/pkg/*.gem
138
+ name: gem-${{ matrix.gem }}-${{ matrix.name }}
139
+ path: sdk/gems/${{ matrix.gem }}/pkg/*.gem
140
141
# ── Build source gem (fallback for unsupported platforms) ──────────────────
142
build-source-gem:
137
- name: Build source gem
143
+ name: Build ${{ matrix.gem }} source gem
144
runs-on: ubuntu-latest
145
+ strategy:
146
+ fail-fast: false
147
+ matrix:
148
+ gem: [auth, model]
149
steps:
150
- name: Checkout
151
uses: actions/checkout@v6
152
with:
143
- ref: ${{ github.event.inputs.tag || github.ref }}
153
+ ref: ${{ inputs.ref || inputs.tag || github.ref }}
154
155
- name: Set the release version
156
shell: bash
@@ -156,13 +166,13 @@ jobs:
166
- name: Verify gem version matches tag
167
shell: bash
168
run: |
159
- GEM_VERSION=$(sed -n "s/.*VERSION = '\(.*\)'/\1/p" sdk/gems/auth/lib/auth/version.rb)
169
+ GEM_VERSION=$(sed -n "s/.*VERSION = '\(.*\)'/\1/p" sdk/gems/${{ matrix.gem }}/lib/${{ matrix.gem }}/version.rb)
170
171
echo "Gem version : ${GEM_VERSION}"
172
echo "Tag version : ${RELEASE_VERSION}"
173
174
if [[ "${GEM_VERSION}" != "${RELEASE_VERSION}" ]]; then
165
- echo "::error::Version mismatch — bump Auth::VERSION in sdk/gems/auth/lib/auth/version.rb before releasing."
175
+ echo "::error::Version mismatch — bump VERSION in sdk/gems/${{ matrix.gem }}/lib/${{ matrix.gem }}/version.rb before releasing."
176
exit 1
177
fi
178
@@ -171,29 +181,33 @@ jobs:
181
with:
182
ruby-version: .ruby-version
183
bundler-cache: true
174
- working-directory: sdk/gems/auth
184
+ working-directory: sdk/gems/${{ matrix.gem }}
185
186
- name: Build source gem
177
- working-directory: sdk/gems/auth
187
+ working-directory: sdk/gems/${{ matrix.gem }}
188
run: bundle exec rake build
189
190
- name: Upload source gem artifact
191
uses: actions/upload-artifact@v7
192
with:
183
- name: gem-source
184
- path: sdk/gems/auth/pkg/*.gem
193
+ name: gem-${{ matrix.gem }}-source
194
+ path: sdk/gems/${{ matrix.gem }}/pkg/*.gem
195
196
# ── Push all gems to RubyGems ──────────────────────────────────────────────
197
push-gems:
188
- name: Push to RubyGems
198
+ name: Push ${{ matrix.gem }} to RubyGems
199
needs: [build-gems, build-source-gem]
200
runs-on: ubuntu-latest
201
+ strategy:
202
+ fail-fast: false
203
+ matrix:
204
+ gem: [auth, model]
205
206
steps:
207
- name: Checkout
208
uses: actions/checkout@v6
209
with:
196
- ref: ${{ github.event.inputs.tag || github.ref }}
210
+ ref: ${{ inputs.ref || inputs.tag || github.ref }}
211
212
- name: Set the release version
213
shell: bash
@@ -211,9 +225,9 @@ jobs:
225
shell: bash
226
run: |
227
if curl -fsS \
214
- "https://rubygems.org/api/v2/rubygems/smbcloud-auth/versions/${RELEASE_VERSION}.json" \
228
+ "https://rubygems.org/api/v2/rubygems/smbcloud-${{ matrix.gem }}/versions/${RELEASE_VERSION}.json" \
229
>/dev/null 2>&1; then
216
- echo "smbcloud-auth ${RELEASE_VERSION} already exists on RubyGems, skipping publish"
230
+ echo "smbcloud-${{ matrix.gem }} ${RELEASE_VERSION} already exists on RubyGems, skipping publish"
231
echo "exists=true" >> "$GITHUB_OUTPUT"
232
else
233
echo "exists=false" >> "$GITHUB_OUTPUT"
@@ -223,7 +237,7 @@ jobs:
237
if: steps.rubygems-check.outputs.exists != 'true'
238
uses: actions/download-artifact@v7
239
with:
226
- pattern: "gem-*"
240
+ pattern: "gem-${{ matrix.gem }}-*"
241
path: gems
242
merge-multiple: true
243
sdk/gems/model/Rakefile
+18
@@ -11,4 +11,22 @@ RbSys::ExtensionTask.new('model', GEMSPEC) do |ext|
11
ext.lib_dir = 'lib/model'
12
end
13
14
+# macOS: the rb_sys/rake-compiler build emits the bundle as an MH_DYLIB with an
15
+# empty LC_ID_DYLIB install name (a plain `cargo build` does not). dyld on macOS
16
+# 15+/Tahoe rejects that with "load command string extends beyond end of load
17
+# command", so the gem fails to load. Stamp a valid install name onto every
18
+# bundle the build produces by enhancing the bundle file tasks themselves (which
19
+# is what `rake native gem` runs, not the top-level `compile`). install_name_tool
20
+# re-signs ad-hoc, ships on the macOS gem-build runners, and works across archs
21
+# (cross-built x86_64 bundles too). Idempotent.
22
+if RbConfig::CONFIG['host_os'] =~ /darwin/
23
+ Rake::Task.tasks.each do |t|
24
+ next unless t.name.end_with?('model.bundle')
25
+
26
+ t.enhance do
27
+ sh 'install_name_tool', '-id', '@rpath/model.bundle', t.name if File.exist?(t.name)
28
+ end
29
+ end
30
+end
31
+
32
task default: :compile