3 files changed
+560
.github/workflows/release-sdk-gem.yml
new
+208
@@ -0,0 +1,208 @@
1
+name: SDK Ruby Gem Release
2
+
3
+# Publishes the smbcloud-auth Ruby gem (sdk/gems/auth) to RubyGems.
4
+# Builds pre-compiled native gems for each supported platform, plus a source
5
+# gem as a fallback for unsupported platforms.
6
+#
7
+# Required secrets:
8
+# RUBYGEMS_API_KEY — RubyGems.org API key with push access to smbcloud-auth
9
+
10
+on:
11
+ push:
12
+ tags:
13
+ - "v*.*.*"
14
+ workflow_dispatch:
15
+ inputs:
16
+ tag:
17
+ description: "Release tag (e.g. v0.3.35)"
18
+ required: true
19
+
20
+permissions:
21
+ contents: read
22
+
23
+env:
24
+ CARGO_TERM_COLOR: always
25
+
26
+jobs:
27
+ # ── Build native gems ──────────────────────────────────────────────────────
28
+ build-gems:
29
+ name: Build gem (${{ matrix.name }})
30
+ runs-on: ${{ matrix.runner }}
31
+ strategy:
32
+ fail-fast: false
33
+ matrix:
34
+ include:
35
+ - { name: linux-x64, runner: ubuntu-latest, platform: x86_64-linux }
36
+ - { name: linux-arm64, runner: ubuntu-24.04-arm, platform: aarch64-linux }
37
+ - { name: darwin-arm64, runner: macos-latest, platform: arm64-darwin }
38
+ - { name: darwin-x64, runner: macos-15-intel, platform: x86_64-darwin }
39
+ - { name: win-x64, runner: windows-2022, platform: x64-mingw-ucrt }
40
+
41
+ steps:
42
+ - name: Checkout
43
+ uses: actions/checkout@v6
44
+ with:
45
+ ref: ${{ github.event.inputs.tag || github.ref }}
46
+
47
+ - name: Read Rust toolchain
48
+ shell: bash
49
+ run: |
50
+ rust_toolchain="$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml | head -n 1)"
51
+ if [ -z "$rust_toolchain" ]; then
52
+ echo "Failed to read Rust toolchain from rust-toolchain.toml" >&2
53
+ exit 1
54
+ fi
55
+ echo "RUST_TOOLCHAIN=${rust_toolchain}" >> "$GITHUB_ENV"
56
+
57
+ - name: Install toolkit
58
+ uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9
59
+ with:
60
+ toolchain: ${{ env.RUST_TOOLCHAIN }}
61
+
62
+ # Scope the Rust cache to the gem's own Cargo workspace so its registry
63
+ # deps are cached independently from the main workspace.
64
+ - name: Setup Rust cache
65
+ uses: Swatinem/rust-cache@v2
66
+ with:
67
+ key: sdk-gem-${{ matrix.name }}
68
+ workspaces: sdk/gems/auth
69
+
70
+ - name: Setup Ruby
71
+ uses: ruby/setup-ruby@v1
72
+ with:
73
+ ruby-version: "3.4.2"
74
+ bundler-cache: true
75
+ working-directory: sdk/gems/auth
76
+
77
+ - name: Build native gem
78
+ working-directory: sdk/gems/auth
79
+ shell: bash
80
+ run: bundle exec rake native gem
81
+
82
+ - name: Upload gem artifact
83
+ uses: actions/upload-artifact@v7
84
+ with:
85
+ name: gem-${{ matrix.name }}
86
+ path: sdk/gems/auth/pkg/*.gem
87
+
88
+ # ── Build source gem (fallback for unsupported platforms) ──────────────────
89
+ build-source-gem:
90
+ name: Build source gem
91
+ runs-on: ubuntu-latest
92
+ steps:
93
+ - name: Checkout
94
+ uses: actions/checkout@v6
95
+ with:
96
+ ref: ${{ github.event.inputs.tag || github.ref }}
97
+
98
+ - name: Set the release version
99
+ shell: bash
100
+ run: |
101
+ if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
102
+ release_version="${GITHUB_REF_NAME#v}"
103
+ else
104
+ release_version="${{ github.event.inputs.tag }}"
105
+ release_version="${release_version#v}"
106
+ fi
107
+ echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
108
+
109
+ - name: Verify gem version matches tag
110
+ shell: bash
111
+ run: |
112
+ GEM_VERSION=$(sed -n "s/.*VERSION = '\\(.*\\)'/\\1/p" sdk/gems/auth/lib/auth/version.rb)
113
+
114
+ echo "Gem version : ${GEM_VERSION}"
115
+ echo "Tag version : ${RELEASE_VERSION}"
116
+
117
+ if [[ "${GEM_VERSION}" != "${RELEASE_VERSION}" ]]; then
118
+ echo "::error::Version mismatch — bump Auth::VERSION in sdk/gems/auth/lib/auth/version.rb before releasing."
119
+ exit 1
120
+ fi
121
+
122
+ - name: Setup Ruby
123
+ uses: ruby/setup-ruby@v1
124
+ with:
125
+ ruby-version: "3.4.2"
126
+ bundler-cache: true
127
+ working-directory: sdk/gems/auth
128
+
129
+ - name: Build source gem
130
+ working-directory: sdk/gems/auth
131
+ run: bundle exec rake build
132
+
133
+ - name: Upload source gem artifact
134
+ uses: actions/upload-artifact@v7
135
+ with:
136
+ name: gem-source
137
+ path: sdk/gems/auth/pkg/*.gem
138
+
139
+ # ── Push all gems to RubyGems ──────────────────────────────────────────────
140
+ push-gems:
141
+ name: Push to RubyGems
142
+ needs: [build-gems, build-source-gem]
143
+ runs-on: ubuntu-latest
144
+
145
+ steps:
146
+ - name: Checkout
147
+ uses: actions/checkout@v6
148
+ with:
149
+ ref: ${{ github.event.inputs.tag || github.ref }}
150
+
151
+ - name: Set the release version
152
+ shell: bash
153
+ run: |
154
+ if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
155
+ release_version="${GITHUB_REF_NAME#v}"
156
+ else
157
+ release_version="${{ github.event.inputs.tag }}"
158
+ release_version="${release_version#v}"
159
+ fi
160
+ echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
161
+
162
+ - name: Check whether release already exists on RubyGems
163
+ id: rubygems-check
164
+ shell: bash
165
+ run: |
166
+ if curl -fsS \
167
+ "https://rubygems.org/api/v2/rubygems/smbcloud-auth/versions/${RELEASE_VERSION}.json" \
168
+ >/dev/null 2>&1; then
169
+ echo "smbcloud-auth ${RELEASE_VERSION} already exists on RubyGems, skipping publish"
170
+ echo "exists=true" >> "$GITHUB_OUTPUT"
171
+ else
172
+ echo "exists=false" >> "$GITHUB_OUTPUT"
173
+ fi
174
+
175
+ - name: Download all gem artifacts
176
+ if: steps.rubygems-check.outputs.exists != 'true'
177
+ uses: actions/download-artifact@v7
178
+ with:
179
+ pattern: "gem-*"
180
+ path: gems
181
+ merge-multiple: true
182
+
183
+ - name: Setup Ruby
184
+ if: steps.rubygems-check.outputs.exists != 'true'
185
+ uses: ruby/setup-ruby@v1
186
+ with:
187
+ ruby-version: "3.4.2"
188
+
189
+ - name: Configure RubyGems credentials
190
+ if: steps.rubygems-check.outputs.exists != 'true'
191
+ shell: bash
192
+ run: |
193
+ mkdir -p "${HOME}/.gem"
194
+ echo ":rubygems_api_key: ${{ secrets.RUBYGEMS_API_KEY }}" > "${HOME}/.gem/credentials"
195
+ chmod 0600 "${HOME}/.gem/credentials"
196
+
197
+ # Push each .gem file individually. Platform-specific gems that are already
198
+ # published (e.g. from a re-run) emit a warning and continue rather than
199
+ # failing the whole job.
200
+ - name: Push gems to RubyGems
201
+ if: steps.rubygems-check.outputs.exists != 'true'
202
+ shell: bash
203
+ run: |
204
+ for gem_file in gems/*.gem; do
205
+ echo "Pushing $(basename "${gem_file}")…"
206
+ gem push "${gem_file}" \
207
+ || echo "::warning::$(basename "${gem_file}") may already exist for this version — skipping."
208
+ done
.github/workflows/release-sdk-npm.yml
new
+118
@@ -0,0 +1,118 @@
1
+name: SDK npm Release
2
+
3
+# Publishes @smbcloud/sdk-auth (WASM) to npm.
4
+# WASM is a single universal target — no platform matrix needed.
5
+#
6
+# Required secrets:
7
+# NPM_TOKEN — npm access token with publish rights to @smbcloud/sdk-auth
8
+
9
+on:
10
+ push:
11
+ tags:
12
+ - "v*.*.*"
13
+ workflow_dispatch:
14
+ inputs:
15
+ tag:
16
+ description: "Release tag (e.g. v0.3.35)"
17
+ required: true
18
+
19
+permissions:
20
+ contents: read
21
+
22
+env:
23
+ CARGO_TERM_COLOR: always
24
+ CLI_CLIENT_SECRET: ${{ secrets.CLI_CLIENT_SECRET }}
25
+
26
+jobs:
27
+ publish-sdk-npm:
28
+ name: Publish @smbcloud/sdk-auth to npm
29
+ runs-on: ubuntu-latest
30
+
31
+ steps:
32
+ - name: Checkout
33
+ uses: actions/checkout@v6
34
+ with:
35
+ ref: ${{ github.event.inputs.tag || github.ref }}
36
+
37
+ - name: Set the release version
38
+ shell: bash
39
+ run: |
40
+ if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
41
+ release_version="${GITHUB_REF_NAME#v}"
42
+ else
43
+ release_version="${{ github.event.inputs.tag }}"
44
+ release_version="${release_version#v}"
45
+ fi
46
+
47
+ echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
48
+
49
+ - name: Read Rust toolchain
50
+ shell: bash
51
+ run: |
52
+ rust_toolchain="$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml | head -n 1)"
53
+ if [ -z "$rust_toolchain" ]; then
54
+ echo "Failed to read Rust toolchain from rust-toolchain.toml" >&2
55
+ exit 1
56
+ fi
57
+
58
+ echo "RUST_TOOLCHAIN=${rust_toolchain}" >> "$GITHUB_ENV"
59
+
60
+ - name: Install toolkit with wasm32 target
61
+ uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9
62
+ with:
63
+ toolchain: ${{ env.RUST_TOOLCHAIN }}
64
+ targets: wasm32-unknown-unknown
65
+
66
+ - name: Setup Rust cache
67
+ uses: Swatinem/rust-cache@v2
68
+ with:
69
+ key: sdk-npm
70
+
71
+ - name: Verify Cargo.toml version matches tag
72
+ shell: bash
73
+ run: |
74
+ CARGO_VERSION=$(cargo metadata --no-deps --format-version 1 \
75
+ | jq -r '.packages[] | select(.name == "smbcloud-auth-sdk-wasm") | .version')
76
+
77
+ echo "Cargo.toml version : ${CARGO_VERSION}"
78
+ echo "Release tag version: ${RELEASE_VERSION}"
79
+
80
+ if [[ "${CARGO_VERSION}" != "${RELEASE_VERSION}" ]]; then
81
+ echo "::error::Version mismatch — bump version in crates/smbcloud-auth-sdk-wasm/Cargo.toml before releasing."
82
+ exit 1
83
+ fi
84
+
85
+ # wasm-pack drives the wasm32 compilation and wasm-bindgen code generation.
86
+ # prepare-package.mjs calls wasm-pack internally and also enforces that
87
+ # sdk/npm/smbcloud-auth/package.json version matches the Cargo.toml version.
88
+ - name: Install wasm-pack
89
+ run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
90
+
91
+ - name: Install Node.js
92
+ uses: actions/setup-node@v6
93
+ with:
94
+ node-version-file: .nvmrc
95
+ registry-url: "https://registry.npmjs.org"
96
+
97
+ - name: Check whether release already exists on npm
98
+ id: npm-check
99
+ shell: bash
100
+ run: |
101
+ if npm view "@smbcloud/sdk-auth@${RELEASE_VERSION}" version >/dev/null 2>&1; then
102
+ echo "@smbcloud/sdk-auth@${RELEASE_VERSION} already exists on npm, skipping publish"
103
+ echo "exists=true" >> "$GITHUB_OUTPUT"
104
+ else
105
+ echo "exists=false" >> "$GITHUB_OUTPUT"
106
+ fi
107
+
108
+ - name: Build and prepare package
109
+ if: steps.npm-check.outputs.exists != 'true'
110
+ working-directory: sdk/npm/smbcloud-auth
111
+ run: node ./prepare-package.mjs
112
+
113
+ - name: Publish to npm
114
+ if: steps.npm-check.outputs.exists != 'true'
115
+ working-directory: sdk/npm/smbcloud-auth
116
+ env:
117
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
118
+ run: npm publish --access public
.github/workflows/release-sdk-pypi.yml
new
+234
@@ -0,0 +1,234 @@
1
+name: SDK PyPI Release
2
+
3
+# Publishes smbcloud-sdk-auth (sdk/python) to PyPI.
4
+# Triggered automatically on semver tags or manually via workflow_dispatch.
5
+
6
+on:
7
+ push:
8
+ tags:
9
+ - "v*.*.*"
10
+ workflow_dispatch:
11
+ inputs:
12
+ tag:
13
+ description: "Release tag (e.g. v0.3.35)"
14
+ required: true
15
+
16
+permissions:
17
+ id-token: write
18
+ contents: read
19
+
20
+env:
21
+ CARGO_TERM_COLOR: always
22
+ CLI_CLIENT_SECRET: ${{ secrets.CLI_CLIENT_SECRET }}
23
+
24
+jobs:
25
+ build-wheels:
26
+ name: Build PyPI wheels
27
+ runs-on: ${{ matrix.build.OS }}
28
+ strategy:
29
+ fail-fast: false
30
+ matrix:
31
+ build:
32
+ - {
33
+ NAME: linux-x64-glibc,
34
+ OS: ubuntu-latest,
35
+ TARGET: x86_64-unknown-linux-gnu,
36
+ MANYLINUX: "2014",
37
+ }
38
+ - {
39
+ NAME: linux-arm64-glibc,
40
+ OS: ubuntu-24.04-arm,
41
+ TARGET: aarch64-unknown-linux-gnu,
42
+ MANYLINUX: "2014",
43
+ }
44
+ - {
45
+ NAME: win32-x64-msvc,
46
+ OS: windows-2022,
47
+ TARGET: x86_64-pc-windows-msvc,
48
+ }
49
+ - {
50
+ NAME: win32-arm64-msvc,
51
+ OS: windows-2022,
52
+ TARGET: aarch64-pc-windows-msvc,
53
+ }
54
+ - { NAME: darwin-x64, OS: macos-15-intel, TARGET: x86_64-apple-darwin }
55
+ - {
56
+ NAME: darwin-arm64,
57
+ OS: macos-latest,
58
+ TARGET: aarch64-apple-darwin,
59
+ }
60
+ steps:
61
+ - name: Checkout
62
+ uses: actions/checkout@v6
63
+ with:
64
+ ref: ${{ github.event.inputs.tag || github.ref }}
65
+
66
+ - name: Set the release version
67
+ shell: bash
68
+ run: |
69
+ if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
70
+ release_version="${GITHUB_REF_NAME#v}"
71
+ else
72
+ release_version="${{ github.event.inputs.tag }}"
73
+ release_version="${release_version#v}"
74
+ fi
75
+
76
+ echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
77
+
78
+ - name: Read Rust toolchain
79
+ shell: bash
80
+ run: |
81
+ rust_toolchain="$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml | head -n 1)"
82
+ if [ -z "$rust_toolchain" ]; then
83
+ echo "Failed to read Rust toolchain from rust-toolchain.toml" >&2
84
+ exit 1
85
+ fi
86
+
87
+ echo "RUST_TOOLCHAIN=${rust_toolchain}" >> "$GITHUB_ENV"
88
+
89
+ - name: Install toolkit
90
+ uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9
91
+ with:
92
+ toolchain: ${{ env.RUST_TOOLCHAIN }}
93
+
94
+ - name: Install Rust target
95
+ shell: bash
96
+ run: |
97
+ rustup target add ${{ matrix.build.TARGET }} --toolchain ${{ env.RUST_TOOLCHAIN }}
98
+ rustup target list --installed
99
+
100
+ - name: Verify Cargo.toml version matches tag
101
+ shell: bash
102
+ run: |
103
+ CARGO_VERSION=$(cargo metadata --no-deps --format-version 1 \
104
+ | jq -r '.packages[] | select(.name == "smbcloud-auth-sdk-py") | .version')
105
+
106
+ echo "Cargo.toml version : ${CARGO_VERSION}"
107
+ echo "Release tag version: ${RELEASE_VERSION}"
108
+
109
+ if [[ "${CARGO_VERSION}" != "${RELEASE_VERSION}" ]]; then
110
+ echo "::error::Version mismatch — bump version in crates/smbcloud-auth-sdk-py/Cargo.toml before releasing."
111
+ exit 1
112
+ fi
113
+
114
+ - name: Setup Rust cache
115
+ uses: Swatinem/rust-cache@v2
116
+ with:
117
+ key: sdk-pypi-${{ matrix.build.NAME }}
118
+
119
+ # manylinux containers are CentOS-based and use yum; perl-core is required
120
+ # by the openssl-sys vendored build to compile OpenSSL from source.
121
+ - name: Build wheel
122
+ uses: PyO3/maturin-action@v1
123
+ with:
124
+ target: ${{ matrix.build.TARGET }}
125
+ manylinux: ${{ matrix.build.MANYLINUX || 'off' }}
126
+ working-directory: sdk/python
127
+ args: --release --locked --compatibility pypi --out dist
128
+ before-script-linux: yum install -y perl-core
129
+ docker-options: -e CLI_CLIENT_SECRET
130
+
131
+ - name: Upload wheel artifact
132
+ uses: actions/upload-artifact@v7
133
+ with:
134
+ name: wheels-${{ matrix.build.NAME }}
135
+ path: sdk/python/dist/*
136
+
137
+ build-sdist:
138
+ name: Build source distribution
139
+ runs-on: ubuntu-latest
140
+ steps:
141
+ - name: Checkout
142
+ uses: actions/checkout@v6
143
+ with:
144
+ ref: ${{ github.event.inputs.tag || github.ref }}
145
+
146
+ - name: Set the release version
147
+ shell: bash
148
+ run: |
149
+ if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
150
+ release_version="${GITHUB_REF_NAME#v}"
151
+ else
152
+ release_version="${{ github.event.inputs.tag }}"
153
+ release_version="${release_version#v}"
154
+ fi
155
+
156
+ echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
157
+
158
+ - name: Read Rust toolchain
159
+ shell: bash
160
+ run: |
161
+ rust_toolchain="$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml | head -n 1)"
162
+ if [ -z "$rust_toolchain" ]; then
163
+ echo "Failed to read Rust toolchain from rust-toolchain.toml" >&2
164
+ exit 1
165
+ fi
166
+
167
+ echo "RUST_TOOLCHAIN=${rust_toolchain}" >> "$GITHUB_ENV"
168
+
169
+ - name: Install toolkit
170
+ uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9
171
+ with:
172
+ toolchain: ${{ env.RUST_TOOLCHAIN }}
173
+
174
+ - name: Build sdist
175
+ uses: PyO3/maturin-action@v1
176
+ with:
177
+ command: sdist
178
+ working-directory: sdk/python
179
+ args: --out dist
180
+
181
+ - name: Upload sdist artifact
182
+ uses: actions/upload-artifact@v7
183
+ with:
184
+ name: sdist
185
+ path: sdk/python/dist/*
186
+
187
+ publish-pypi:
188
+ name: Publish to PyPI
189
+ runs-on: ubuntu-latest
190
+ needs:
191
+ - build-wheels
192
+ - build-sdist
193
+
194
+ steps:
195
+ - name: Checkout
196
+ uses: actions/checkout@v6
197
+ with:
198
+ ref: ${{ github.event.inputs.tag || github.ref }}
199
+
200
+ - name: Set the release version
201
+ shell: bash
202
+ run: |
203
+ if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
204
+ release_version="${GITHUB_REF_NAME#v}"
205
+ else
206
+ release_version="${{ github.event.inputs.tag }}"
207
+ release_version="${release_version#v}"
208
+ fi
209
+
210
+ echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
211
+
212
+ - name: Download distribution artifacts
213
+ uses: actions/download-artifact@v7
214
+ with:
215
+ pattern: "*"
216
+ path: dist
217
+ merge-multiple: true
218
+
219
+ - name: Check whether release already exists on PyPI
220
+ id: pypi-check
221
+ shell: bash
222
+ run: |
223
+ if curl -fsS "https://pypi.org/pypi/smbcloud-sdk-auth/${RELEASE_VERSION}/json" >/dev/null 2>&1; then
224
+ echo "smbcloud-sdk-auth ${RELEASE_VERSION} already exists on PyPI, skipping publish"
225
+ echo "exists=true" >> "$GITHUB_OUTPUT"
226
+ else
227
+ echo "exists=false" >> "$GITHUB_OUTPUT"
228
+ fi
229
+
230
+ - name: Publish distribution
231
+ if: steps.pypi-check.outputs.exists != 'true'
232
+ uses: pypa/gh-action-pypi-publish@release/v1
233
+ with:
234
+ skip-existing: true