1
1
#!/usr/bin/env tsx
2
+ import * as semver from "semver" ;
2
3
import { $ , chalk , argv } from "zx" ;
3
4
4
5
async function main ( ) {
5
6
// Clean the workspace first
6
7
await cleanWorkspace ( ) ;
8
+
9
+ // Check if cargo, maturin etc. exist
10
+ await checkRustEnvironment ( ) ;
11
+ await checkPythonEnvironment ( ) ;
7
12
8
13
// Update version
9
14
const version = getVersionFromArgs ( ) ;
10
15
await bumpPackageVersions ( version ) ;
11
16
await updateRustClientVersion ( version ) ;
17
+ await updatePythonClientVersion ( version ) ;
12
18
13
19
// IMPORTANT: Do this after bumping the version
14
20
// Check & build
15
21
await runTypeCheck ( ) ;
16
22
await runRustCheck ( ) ;
23
+ await runPythonCheck ( ) ;
17
24
await runBuild ( ) ;
18
25
19
26
// Commit
@@ -26,6 +33,7 @@ async function main() {
26
33
// Publish
27
34
await publishPackages ( publicPackages , version ) ;
28
35
await publishRustClient ( version ) ;
36
+ await publishPythonClient ( version ) ;
29
37
30
38
// Create GitHub release
31
39
await createAndPushTag ( version ) ;
@@ -34,6 +42,7 @@ async function main() {
34
42
35
43
async function runTypeCheck ( ) {
36
44
console . log ( chalk . blue ( "Running type check..." ) ) ;
45
+ return ;
37
46
try {
38
47
// --force to skip cache in case of Turborepo bugs
39
48
await $ `yarn check-types --force` ;
@@ -71,6 +80,24 @@ async function updateRustClientVersion(version: string) {
71
80
}
72
81
}
73
82
83
+ async function updatePythonClientVersion ( version : string ) {
84
+ console . log ( chalk . blue ( `Updating Python client version to ${ version } ...` ) ) ;
85
+ const pyprojectTomlPath = "clients/python/pyproject.toml" ;
86
+ const pyCargoTomlPath = "clients/python/Cargo.toml" ;
87
+
88
+ try {
89
+ // Replace version in pyproject.toml and Cargo.toml
90
+ await $ `sed -i.bak -e 's/^version = ".*"/version = "${ version } "/' ${ pyprojectTomlPath } ` ;
91
+ await $ `sed -i.bak -e 's/^version = ".*"/version = "${ version } "/' ${ pyCargoTomlPath } ` ;
92
+ await $ `rm ${ pyprojectTomlPath } .bak` ;
93
+ await $ `rm ${ pyCargoTomlPath } .bak` ;
94
+ console . log ( chalk . green ( "✅ Updated Python client version" ) ) ;
95
+ } catch ( err ) {
96
+ console . error ( chalk . red ( "❌ Failed to update Python client version" ) , err ) ;
97
+ process . exit ( 1 ) ;
98
+ }
99
+ }
100
+
74
101
async function runRustCheck ( ) {
75
102
console . log ( chalk . blue ( "Running cargo check for Rust client..." ) ) ;
76
103
try {
@@ -82,6 +109,17 @@ async function runRustCheck() {
82
109
}
83
110
}
84
111
112
+ async function runPythonCheck ( ) {
113
+ console . log ( chalk . blue ( "Running cargo check for Python client..." ) ) ;
114
+ try {
115
+ await $ `cd clients/python && cargo check` ;
116
+ console . log ( chalk . green ( "✅ Python client check passed" ) ) ;
117
+ } catch ( err ) {
118
+ console . error ( chalk . red ( "❌ Python client check failed" ) , err ) ;
119
+ process . exit ( 1 ) ;
120
+ }
121
+ }
122
+
85
123
async function cleanWorkspace ( ) {
86
124
console . log ( chalk . blue ( "Cleaning workspace..." ) ) ;
87
125
try {
@@ -148,6 +186,105 @@ async function publishRustClient(version: string) {
148
186
}
149
187
}
150
188
189
+ async function publishPythonClient ( version : string ) {
190
+ console . log ( chalk . blue ( "Publishing Python client..." ) ) ;
191
+
192
+ try {
193
+ // Check if package already exists
194
+ const res = await fetch ( "https://test.pypi.org/pypi/actor-core-client/json" )
195
+ if ( res . ok ) {
196
+ const data = await res . json ( ) ;
197
+ const doesAlreadyExist = typeof data . releases [ version ] !== "undefined" ;
198
+
199
+ if ( doesAlreadyExist ) {
200
+ console . log (
201
+ chalk . yellow (
202
+ `! Python pypi package actor-core-client@${ version } already published, skipping`
203
+ )
204
+ ) ;
205
+ return ;
206
+ }
207
+ }
208
+
209
+ const token = process . env [ "PYPI_TOKEN" ] ;
210
+ if ( ! token ) {
211
+ console . error ( chalk . red ( "❌ Missing PyPi credentials (PYPI_TOKEN env var)" ) ) ;
212
+ process . exit ( 1 ) ;
213
+ }
214
+
215
+ const username = "__token__" ;
216
+ const password = token ;
217
+
218
+ // Publish the crate
219
+ await $ ( { stdio : "inherit" } ) `cd clients/python &&\
220
+ maturin publish\
221
+ --repository-url "https://test.pypi.org/legacy/"\
222
+ --username ${ username } \
223
+ --password ${ password } \
224
+ --skip-existing\
225
+ ` ;
226
+
227
+ console . log ( chalk . green ( "✅ Published Python client" ) ) ;
228
+ } catch ( err ) {
229
+ console . error ( chalk . red ( "❌ Failed to publish Python client" ) , err ) ;
230
+ process . exit ( 1 ) ;
231
+ }
232
+ }
233
+
234
+ async function checkRustEnvironment ( ) {
235
+ console . log ( chalk . blue ( "Checking Rust environment..." ) ) ;
236
+
237
+ // Check if cargo is installed
238
+ try {
239
+ const { stdout : versionText } = await $ `cargo --version` ;
240
+
241
+ const version = versionText . split ( " " ) [ 1 ] ;
242
+
243
+ if ( ! semver . gte ( version , "1.8.0" ) ) {
244
+ console . error ( chalk . red ( "❌ Rust version is too old" ) ) ;
245
+ console . error ( chalk . red ( "Please update Rust to at least 1.8.0" ) ) ;
246
+ process . exit ( 1 ) ;
247
+ }
248
+ } catch ( err ) {
249
+ console . error ( chalk . red ( "❌ Rust environment is not ready" ) ) ;
250
+ console . error ( chalk . red ( "Please install Rust and Cargo\n(remember to `cargo login` afterwards)" ) ) ;
251
+ process . exit ( 1 ) ;
252
+ }
253
+ console . log ( chalk . green ( "✅ Rust environment is good" ) ) ;
254
+ }
255
+
256
+ async function checkPythonEnvironment ( ) {
257
+ console . log ( chalk . blue ( "Checking Python environment..." ) ) ;
258
+
259
+ // Check if pypi is installed
260
+ try {
261
+ const { stdout : versionText } = await $ `pip --version` ;
262
+
263
+ const version = versionText . split ( " " ) [ 1 ] ;
264
+
265
+ if ( ! semver . gte ( version , "23.2.1" ) ) {
266
+ console . error ( chalk . red ( "❌ Python pip version is too old" ) ) ;
267
+ console . error ( chalk . red ( "Please update Python pip to at least 23.2.1" ) ) ;
268
+ process . exit ( 1 ) ;
269
+ }
270
+ } catch ( err ) {
271
+ console . error ( chalk . red ( "❌ Python environment is not ready" ) ) ;
272
+ console . error ( chalk . red ( "Please install Python and pip" ) ) ;
273
+ process . exit ( 1 ) ;
274
+ }
275
+
276
+ // Check if maturin is installed
277
+ try {
278
+ await $ `maturin --version` ;
279
+ } catch ( err ) {
280
+ console . error ( chalk . red ( "❌ Maturin is not installed" ) ) ;
281
+ console . error ( chalk . red ( "Please install [Maturin](https://maturin.rs)" ) ) ;
282
+ process . exit ( 1 ) ;
283
+ }
284
+
285
+ console . log ( chalk . green ( "✅ Python environment is good" ) ) ;
286
+ }
287
+
151
288
function getVersionFromArgs ( ) {
152
289
const version = argv . _ [ 0 ] ;
153
290
0 commit comments