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