@smbcloud / cli / commits / 47b5c8e

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