1 name: SDK PyPI Release
2
3 # Publishes smbcloud-sdk-auth (sdk/python) to PyPI.
4 # Triggered by the crates release workflow when wrapped Rust crates change,
5 # or manually via workflow_dispatch.
6 #
7 # Windows arm64 wheels are intentionally not built here. GitHub's hosted
8 # Windows runners provide x64 Python, and maturin refuses to build an arm64
9 # wheel when the interpreter reports win-amd64.
10
11 on:
12 workflow_dispatch:
13 inputs:
14 tag:
15 description: "Release tag (e.g. v0.3.35)"
16 required: true
17
18 permissions:
19 id-token: write
20 contents: read
21
22 env:
23 CARGO_TERM_COLOR: always
24 CLI_CLIENT_SECRET: ${{ secrets.CLI_CLIENT_SECRET }}
25
26 jobs:
27 build-wheels:
28 name: Build PyPI wheels
29 runs-on: ${{ matrix.build.OS }}
30 strategy:
31 fail-fast: false
32 matrix:
33 build:
34 - {
35 NAME: linux-x64-glibc,
36 OS: ubuntu-latest,
37 TARGET: x86_64-unknown-linux-gnu,
38 MANYLINUX: "2014",
39 }
40 - {
41 NAME: linux-arm64-glibc,
42 OS: ubuntu-24.04-arm,
43 TARGET: aarch64-unknown-linux-gnu,
44 MANYLINUX: "2014",
45 }
46 - {
47 NAME: win32-x64-msvc,
48 OS: windows-2022,
49 TARGET: x86_64-pc-windows-msvc,
50 }
51 - {
52 NAME: darwin-x64,
53 OS: macos-15-intel,
54 TARGET: x86_64-apple-darwin,
55 }
56 - {
57 NAME: darwin-arm64,
58 OS: macos-latest,
59 TARGET: aarch64-apple-darwin,
60 }
61 steps:
62 - name: Checkout
63 uses: actions/checkout@v6
64 with:
65 ref: ${{ github.event.inputs.tag || github.ref }}
66
67 - name: Set the release version
68 shell: bash
69 run: |
70 if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
71 release_version="${GITHUB_REF_NAME#v}"
72 else
73 release_version="${{ github.event.inputs.tag }}"
74 release_version="${release_version#v}"
75 fi
76
77 echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
78
79 - name: Read Rust toolchain
80 shell: bash
81 run: |
82 rust_toolchain="$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml | head -n 1)"
83 if [ -z "$rust_toolchain" ]; then
84 echo "Failed to read Rust toolchain from rust-toolchain.toml" >&2
85 exit 1
86 fi
87
88 echo "RUST_TOOLCHAIN=${rust_toolchain}" >> "$GITHUB_ENV"
89
90 - name: Install toolkit
91 uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9
92 with:
93 toolchain: ${{ env.RUST_TOOLCHAIN }}
94
95 - name: Install Rust target
96 shell: bash
97 run: |
98 rustup target add ${{ matrix.build.TARGET }} --toolchain ${{ env.RUST_TOOLCHAIN }}
99 rustup target list --installed
100
101 - name: Verify Cargo.toml version matches tag
102 shell: bash
103 run: |
104 CARGO_VERSION=$(cargo metadata --no-deps --format-version 1 \
105 | jq -r '.packages[] | select(.name == "smbcloud-auth-sdk-py") | .version')
106
107 echo "Cargo.toml version : ${CARGO_VERSION}"
108 echo "Release tag version: ${RELEASE_VERSION}"
109
110 if [[ "${CARGO_VERSION}" != "${RELEASE_VERSION}" ]]; then
111 echo "::error::Version mismatch — bump version in crates/smbcloud-auth-sdk-py/Cargo.toml before releasing."
112 exit 1
113 fi
114
115 - name: Setup Rust cache
116 uses: Swatinem/rust-cache@v2
117 with:
118 key: sdk-pypi-${{ matrix.build.NAME }}
119
120 # manylinux containers are CentOS-based and use yum; perl-core is required
121 # by the openssl-sys vendored build to compile OpenSSL from source.
122 - name: Build wheel
123 uses: PyO3/maturin-action@v1
124 with:
125 target: ${{ matrix.build.TARGET }}
126 manylinux: ${{ matrix.build.MANYLINUX || 'off' }}
127 working-directory: sdk/python
128 args: --release --locked --compatibility pypi --out dist
129 before-script-linux: yum install -y perl-core
130 docker-options: -e CLI_CLIENT_SECRET
131
132 - name: Upload wheel artifact
133 uses: actions/upload-artifact@v7
134 with:
135 name: wheels-${{ matrix.build.NAME }}
136 path: sdk/python/dist/*
137
138 build-sdist:
139 name: Build source distribution
140 runs-on: ubuntu-latest
141 steps:
142 - name: Checkout
143 uses: actions/checkout@v6
144 with:
145 ref: ${{ github.event.inputs.tag || github.ref }}
146
147 - name: Set the release version
148 shell: bash
149 run: |
150 if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
151 release_version="${GITHUB_REF_NAME#v}"
152 else
153 release_version="${{ github.event.inputs.tag }}"
154 release_version="${release_version#v}"
155 fi
156
157 echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
158
159 - name: Read Rust toolchain
160 shell: bash
161 run: |
162 rust_toolchain="$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml | head -n 1)"
163 if [ -z "$rust_toolchain" ]; then
164 echo "Failed to read Rust toolchain from rust-toolchain.toml" >&2
165 exit 1
166 fi
167
168 echo "RUST_TOOLCHAIN=${rust_toolchain}" >> "$GITHUB_ENV"
169
170 - name: Install toolkit
171 uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9
172 with:
173 toolchain: ${{ env.RUST_TOOLCHAIN }}
174
175 - name: Build sdist
176 uses: PyO3/maturin-action@v1
177 with:
178 command: sdist
179 working-directory: sdk/python
180 args: --out dist
181
182 - name: Upload sdist artifact
183 uses: actions/upload-artifact@v7
184 with:
185 name: sdist
186 path: sdk/python/dist/*
187
188 publish-pypi:
189 name: Publish to PyPI
190 runs-on: ubuntu-latest
191 needs:
192 - build-wheels
193 - build-sdist
194
195 steps:
196 - name: Checkout
197 uses: actions/checkout@v6
198 with:
199 ref: ${{ github.event.inputs.tag || github.ref }}
200
201 - name: Set the release version
202 shell: bash
203 run: |
204 if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
205 release_version="${GITHUB_REF_NAME#v}"
206 else
207 release_version="${{ github.event.inputs.tag }}"
208 release_version="${release_version#v}"
209 fi
210
211 echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
212
213 - name: Download distribution artifacts
214 uses: actions/download-artifact@v7
215 with:
216 pattern: "*"
217 path: dist
218 merge-multiple: true
219
220 - name: Check whether release already exists on PyPI
221 id: pypi-check
222 shell: bash
223 run: |
224 if curl -fsS "https://pypi.org/pypi/smbcloud-sdk-auth/${RELEASE_VERSION}/json" >/dev/null 2>&1; then
225 echo "smbcloud-sdk-auth ${RELEASE_VERSION} already exists on PyPI, skipping publish"
226 echo "exists=true" >> "$GITHUB_OUTPUT"
227 else
228 echo "exists=false" >> "$GITHUB_OUTPUT"
229 fi
230
231 - name: Publish distribution
232 if: steps.pypi-check.outputs.exists != 'true'
233 uses: pypa/gh-action-pypi-publish@release/v1
234 with:
235 skip-existing: true