mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-18 08:01:26 +00:00
feat(rust): add rust sdk (#5909)
* upload client * add gh workflow * refactor build script * remove dbg! * fix async * remove unused * update dev.nu * update CI * fix ci * fixin tests * fixes + tests
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
name: Publish rust-client to crates.io on release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build_rust_and_publish_to_crates_io:
|
||||
runs-on: ubicloud-standard-8
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v20
|
||||
with:
|
||||
extra_nix_config: |
|
||||
experimental-features = nix-command flakes
|
||||
- run: cd rust-client && nix develop ../ --command ./dev.nu --check --publish
|
||||
env:
|
||||
CRATES_IO_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
|
||||
@@ -0,0 +1,3 @@
|
||||
windmill-api/
|
||||
windmill_api/
|
||||
api/
|
||||
Generated
+1821
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,47 @@
|
||||
[package]
|
||||
name = "wmill"
|
||||
version = """
|
||||
1.496.3
|
||||
"""
|
||||
edition = "2024"
|
||||
description = "A client library for accessing Windmill server wrapping the Windmill client API"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://windmill.dev"
|
||||
|
||||
[workspace]
|
||||
resolver = "3"
|
||||
members = ["windmill_api"]
|
||||
|
||||
[dependencies]
|
||||
serde_yaml = "0.9"
|
||||
serde_json = "1.0"
|
||||
serde = "1.0"
|
||||
thiserror = "2"
|
||||
anyhow = "1.0"
|
||||
uuid = "1"
|
||||
|
||||
[dependencies.windmill-api]
|
||||
path = "./windmill_api"
|
||||
version = "1.496.3"
|
||||
|
||||
[dependencies.futures]
|
||||
version = "0.3"
|
||||
|
||||
[dependencies.tokio]
|
||||
version = "1"
|
||||
default-features = false
|
||||
|
||||
[dependencies.once_cell]
|
||||
version = "1.18"
|
||||
|
||||
[dev-dependencies.tokio]
|
||||
version = "1"
|
||||
default-features = false
|
||||
features = [
|
||||
"rt",
|
||||
"macros",
|
||||
]
|
||||
|
||||
[features]
|
||||
default = []
|
||||
async = []
|
||||
@@ -0,0 +1,195 @@
|
||||
# Windmill Rust SDK
|
||||
|
||||
A Rust client library for interacting with [Windmill](https://www.windmill.dev/) API, providing type-safe abstractions for variables, resources, scripts, jobs, and state management.
|
||||
|
||||
## Installation
|
||||
|
||||
Add this to your ```Cargo.toml```:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
wmill = "0.1.0"
|
||||
```
|
||||
|
||||
For async support (recommended):
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
wmill = { version = "0.1.0", features = ["async"] }
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Initialize Client
|
||||
|
||||
```ignore
|
||||
use wmill::Windmill;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Read config from env vars
|
||||
let wm = Windmill::default()?;
|
||||
|
||||
// Or override specific values
|
||||
let wm = Windmill::new(
|
||||
Some("custom_token".to_string()),
|
||||
Some("my_workspace".to_string()),
|
||||
Some("http://localhost:8000".to_string())
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
### Variables
|
||||
|
||||
```ignore
|
||||
// Get variable (auto-parsed)
|
||||
let db_config: serde_json::Value = wm.get_variable("u/admin/db_config").await?;
|
||||
|
||||
// Get raw variable
|
||||
let raw_text = wm.get_variable_raw("u/user/text_note").await?;
|
||||
|
||||
// Set variable
|
||||
wm.set_variable("new_value".to_string(), "u/user/my_var", false).await?;
|
||||
```
|
||||
|
||||
### Resources
|
||||
|
||||
```ignore
|
||||
// Get resource (typed)
|
||||
#[derive(serde::Deserialize)]
|
||||
struct DbConfig { host: String, port: u16 }
|
||||
|
||||
let config: DbConfig = wm.get_resource("u/admin/db").await?;
|
||||
|
||||
// Get raw resource
|
||||
let raw_json = wm.get_resource_any("u/admin/db").await?;
|
||||
|
||||
// Set resource
|
||||
wm.set_resource(
|
||||
Some(serde_json::json!({"host": "localhost", "port": 5432})),
|
||||
"u/admin/db",
|
||||
"postgresql"
|
||||
).await?;
|
||||
```
|
||||
|
||||
### Scripts
|
||||
|
||||
```ignore
|
||||
// Run script async
|
||||
let job_id = wm.run_script_async(
|
||||
"u/user/my_script",
|
||||
false,
|
||||
serde_json::json!({"param": "value"}),
|
||||
Some(10) // Schedule in 10 seconds
|
||||
).await?;
|
||||
|
||||
// Run script sync
|
||||
let result = wm.run_script_sync(
|
||||
"u/user/my_script",
|
||||
false,
|
||||
serde_json::json!({"param": "value"}),
|
||||
Some(10),
|
||||
Some(30), // 30s timeout
|
||||
true, // Verbose
|
||||
true // Assert result not None
|
||||
).await?;
|
||||
```
|
||||
|
||||
### Jobs
|
||||
|
||||
```ignore
|
||||
// Wait for job completion
|
||||
let result = wm.wait_job(&job_id, Some(60), true, true).await?;
|
||||
|
||||
// Get job status
|
||||
let status = wm.get_job_status(&job_id).await?; // Running/Waiting/Completed
|
||||
|
||||
// Get result directly
|
||||
let result = wm.get_result(&job_id).await?;
|
||||
```
|
||||
|
||||
### State Management
|
||||
|
||||
```ignore
|
||||
// Get typed state
|
||||
#[derive(serde::Deserialize)]
|
||||
struct ScriptState { counter: i32 }
|
||||
|
||||
let state: ScriptState = wm.get_state().await?;
|
||||
|
||||
// Get raw state
|
||||
let raw_state = wm.get_state_any().await?;
|
||||
|
||||
// Update state
|
||||
wm.set_state(Some(serde_json::json!({"counter": 42}))).await?;
|
||||
```
|
||||
|
||||
### Progress Tracking
|
||||
|
||||
```ignore
|
||||
// Set job progress
|
||||
wm.set_progress(75, None).await?; // Uses current job ID from env
|
||||
|
||||
// Get job progress
|
||||
let progress = wm.get_progress(Some(job_id.to_string())).await?;
|
||||
```
|
||||
|
||||
### Custom API Calls
|
||||
|
||||
The SDK provides direct access to underlying API endpoints through the ```call_api``` method, which works in both async and sync contexts:
|
||||
|
||||
```ignore
|
||||
// Async usage
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let wm = Windmill::default()?;
|
||||
|
||||
// Make direct API call to get user
|
||||
let user = wm.call_api(wmill::apis::admin_api::get_user(
|
||||
&wm.client_config,
|
||||
&wm.workspace,
|
||||
"Alice"
|
||||
)).await;
|
||||
|
||||
println!("User details: {:?}", user);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Sync usage
|
||||
fn main() {
|
||||
let wm = Windmill::default().unwrap();
|
||||
|
||||
// Make direct API call to get user
|
||||
let user = wm.call_api(wmill::apis::admin_api::get_user(
|
||||
&wm.client_config,
|
||||
&wm.workspace,
|
||||
"Bob"
|
||||
));
|
||||
|
||||
println!("User details: {:?}", user);
|
||||
}
|
||||
```
|
||||
|
||||
This advanced feature allows access to any Windmill API endpoint, even those not covered by the SDK's convenience methods. Use this when:
|
||||
- Need to access newer/undocumented API endpoints
|
||||
- Require fine-grained control over API requests
|
||||
- Existing abstractions don't meet specific needs
|
||||
|
||||
## Environment Variables
|
||||
|
||||
The SDK uses these environment variables:
|
||||
|
||||
| Variable | Required | Description |
|
||||
|---------|----------|-------------|
|
||||
| ```WM_TOKEN``` | ✅ | Authentication token |
|
||||
| ```WM_WORKSPACE``` | ✅ | Workspace name |
|
||||
| ```BASE_INTERNAL_URL``` | ✅ | API base URL (without ```/api```) |
|
||||
| ```WM_JOB_ID``` | Optional | Current job ID for progress tracking |
|
||||
| ```WM_STATE_PATH_NEW``` | Optional | State path override |
|
||||
|
||||
## Contributions
|
||||
|
||||
Contributions are welcome! Please open an issue or submit a PR.
|
||||
|
||||
Executable
+81
@@ -0,0 +1,81 @@
|
||||
#! /usr/bin/env nu
|
||||
|
||||
let version = open ../version.txt;
|
||||
|
||||
def main [ --publish(-p) --check(-c) --test(-t) ] {
|
||||
mkdir api/a/
|
||||
|
||||
open ../backend/windmill-api/openapi.yaml
|
||||
# openapi-generator confused with these two, so we just drop them
|
||||
| reject paths."/w/{workspace}/apps/create_raw"
|
||||
| reject paths."/w/{workspace}/apps/update_raw/{path}"
|
||||
| save -f api/openapi.yaml;
|
||||
|
||||
openapi-generator-cli generate -i api/openapi.yaml -g rust -o ./windmill_api --strict-spec true --additional-properties=packageName="windmill-api"
|
||||
|
||||
# Patch Cargo.toml
|
||||
open Cargo.toml
|
||||
| update package.version $version
|
||||
| save -f Cargo.toml
|
||||
|
||||
# Patch windmill_api/Cargo.toml
|
||||
open windmill_api/Cargo.toml
|
||||
# Use rustls - otherwise compilation will fail due to missing libssl
|
||||
| update dependencies.reqwest.features [json, multipart, rustls-tls]
|
||||
| insert dependencies.reqwest.default-features false
|
||||
| update package.license "Apache-2.0"
|
||||
| insert package.homepage "https://windmill.dev"
|
||||
| save -f windmill_api/Cargo.toml
|
||||
|
||||
# Recursively replace serde_json::from_str with our patched version
|
||||
ls ./windmill_api/src/**/*.rs
|
||||
| each { |file|
|
||||
let path = $file.name
|
||||
open $path
|
||||
| str replace --all "serde_json::from_str" "crate::from_str_patched/* Externally injected from /build.nu */"
|
||||
| save -f $path
|
||||
}
|
||||
|
||||
# Inject patched from_str
|
||||
echo `
|
||||
// NOTE: Injected by rust-client/dev.nu
|
||||
pub fn from_str_patched<'a, T>(s: &'a str) -> Result<T, serde_json::Error>
|
||||
where
|
||||
T: serde::de::DeserializeOwned + 'static,
|
||||
{
|
||||
if std::any::TypeId::of::<T>() == std::any::TypeId::of::<String>()
|
||||
|| std::any::TypeId::of::<T>() == std::any::TypeId::of::<uuid::Uuid>() {
|
||||
// unsafe { std::mem::transmute::<&str, T>(s) }
|
||||
// Quote string
|
||||
let a = format!("\"{}\"", s.replace('"', r#"\""#));
|
||||
serde_json::from_str(&a)
|
||||
} else {
|
||||
serde_json::from_str(s)
|
||||
}
|
||||
}
|
||||
` | save --append ./windmill_api/src/lib.rs
|
||||
|
||||
if $check {
|
||||
print "Checking..."
|
||||
cargo check --no-default-features
|
||||
cargo check --features "async"
|
||||
}
|
||||
|
||||
if $test {
|
||||
print "Testing..."
|
||||
cargo test --features async simple
|
||||
cargo test --no-default-features
|
||||
}
|
||||
|
||||
if $publish {
|
||||
print "Publishing..."
|
||||
|
||||
print Publishing windmill-api
|
||||
cd windmill_api
|
||||
cargo publish --token $env.CRATES_IO_TOKEN --allow-dirty
|
||||
|
||||
print Publishing wmill
|
||||
cd ../
|
||||
cargo publish --token $env.CRATES_IO_TOKEN --allow-dirty
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
#![doc = include_str!("../README.md")]
|
||||
mod client;
|
||||
mod maybe_future;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use client::{SdkError, Windmill};
|
||||
pub use windmill_api::apis;
|
||||
@@ -0,0 +1,48 @@
|
||||
// #[cfg(feature = "async")]
|
||||
// use futures::future::BoxFuture;
|
||||
|
||||
/// A conditional type that represents either:
|
||||
/// - A boxed future (async mode)
|
||||
/// - A direct value (sync mode)
|
||||
pub mod maybe_future {
|
||||
#[cfg(feature = "async")]
|
||||
pub type MaybeFuture<'a, T> = futures::future::BoxFuture<'a, T>;
|
||||
#[cfg(not(feature = "async"))]
|
||||
pub type MaybeFuture<'a, T> = T;
|
||||
}
|
||||
|
||||
/// Bridges between async and sync execution contexts
|
||||
///
|
||||
/// Behavior depends on compilation:
|
||||
/// - With `async` feature: Returns a boxed future
|
||||
/// - Without `async` feature: Blocks on the global runtime
|
||||
#[macro_export]
|
||||
macro_rules! ret {
|
||||
($ex:expr) => {
|
||||
#[cfg(feature = "async")]
|
||||
return async move { $ex.await }.boxed();
|
||||
|
||||
#[cfg(not(feature = "async"))]
|
||||
return crate::maybe_future::RUNTIME.block_on($ex);
|
||||
};
|
||||
}
|
||||
|
||||
/// The global Tokio runtime instance used in sync mode
|
||||
///
|
||||
/// Initialized lazily with:
|
||||
/// - I/O capabilities
|
||||
/// - Time utilities
|
||||
/// - Current-thread executor
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// If Tokio fails to initialize the runtime
|
||||
#[cfg(not(feature = "async"))]
|
||||
pub(crate) static RUNTIME: once_cell::sync::Lazy<tokio::runtime::Runtime> =
|
||||
once_cell::sync::Lazy::new(|| {
|
||||
tokio::runtime::Builder::new_current_thread()
|
||||
.enable_io()
|
||||
.enable_time()
|
||||
.build()
|
||||
.unwrap()
|
||||
});
|
||||
@@ -0,0 +1,345 @@
|
||||
use serde::Deserialize;
|
||||
use serde_json::json;
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn wm() -> Windmill {
|
||||
Windmill::new(
|
||||
// Some("<WM_TOKEN>".into()),
|
||||
None,
|
||||
Some("admins".into()),
|
||||
// Some("storage".into()),
|
||||
Some("http://localhost:8000".into()),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "async"))]
|
||||
#[test]
|
||||
fn create() {
|
||||
wm();
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "async"))]
|
||||
#[test]
|
||||
fn resources() {
|
||||
#[derive(Deserialize, Debug, PartialEq, PartialOrd)]
|
||||
struct MatrixResource {
|
||||
token: String,
|
||||
#[allow(non_snake_case)]
|
||||
baseUrl: String,
|
||||
}
|
||||
let wm = wm();
|
||||
let path = format!("f/tests/delete_me_{}", Uuid::new_v4());
|
||||
|
||||
{
|
||||
wm.set_resource(
|
||||
Some(json!({
|
||||
"token": "token",
|
||||
"baseUrl": "url"
|
||||
})),
|
||||
&path,
|
||||
"matrix",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let matrix: MatrixResource = wm.get_resource(&path).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
MatrixResource {
|
||||
token: "token".into(),
|
||||
baseUrl: "url".into()
|
||||
},
|
||||
matrix
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "async"))]
|
||||
#[test]
|
||||
fn variables() {
|
||||
let wm = wm();
|
||||
let path = format!("f/tests/delete_me_{}", Uuid::new_v4());
|
||||
|
||||
{
|
||||
// Create new
|
||||
wm.set_variable(
|
||||
":0".into(),
|
||||
&path,
|
||||
// TODO: Test with true
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Read
|
||||
let out_val = wm.get_variable_raw(&path).unwrap();
|
||||
assert_eq!(":0", &out_val);
|
||||
}
|
||||
{
|
||||
// Update
|
||||
let in_val = json!({
|
||||
"a": true,
|
||||
"b": "c"
|
||||
});
|
||||
|
||||
wm.set_variable(
|
||||
// Serialize as JSON
|
||||
serde_yaml::to_string(&in_val).unwrap(),
|
||||
&path,
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Read Updated
|
||||
let out_val = wm.get_variable(&path).unwrap();
|
||||
|
||||
assert_eq!(in_val, out_val);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "async"))]
|
||||
#[test]
|
||||
fn create_and_run() {
|
||||
let wm = wm();
|
||||
|
||||
let path = format!("f/tests/delete_me_{}", Uuid::new_v4());
|
||||
let resp = wm
|
||||
.call_api(apis::script_api::create_script(
|
||||
&wm.client_config,
|
||||
&wm.workspace,
|
||||
windmill_api::models::NewScript {
|
||||
path: path.clone(),
|
||||
parent_hash: None,
|
||||
summary: "auto-generated script from rust sdk | testing".into(),
|
||||
description: "auto-generated script from rust sdk | testing".into(),
|
||||
content: r#"fn main() -> Result<String, String> { Ok("Hello World!".to_owned()) }"#
|
||||
.into(),
|
||||
schema: None,
|
||||
is_template: None,
|
||||
lock: None,
|
||||
language: windmill_api::models::ScriptLang::Rust,
|
||||
kind: Some(windmill_api::models::new_script::Kind::Script),
|
||||
tag: Some("rust".into()),
|
||||
draft_only: None,
|
||||
envs: None,
|
||||
concurrent_limit: None,
|
||||
concurrency_time_window_s: None,
|
||||
cache_ttl: None,
|
||||
dedicated_worker: None,
|
||||
ws_error_handler_muted: None,
|
||||
priority: None,
|
||||
restart_unless_cancelled: None,
|
||||
timeout: None,
|
||||
delete_after_use: None,
|
||||
deployment_message: None,
|
||||
concurrency_key: None,
|
||||
visible_to_runner_only: None,
|
||||
no_main_func: None,
|
||||
codebase: None,
|
||||
has_preprocessor: None,
|
||||
on_behalf_of_email: None,
|
||||
},
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
json!("Hello World!"),
|
||||
wm.run_script_sync(
|
||||
//
|
||||
&resp,
|
||||
true,
|
||||
json!(null),
|
||||
None,
|
||||
None,
|
||||
true,
|
||||
false,
|
||||
)
|
||||
.unwrap()
|
||||
);
|
||||
}
|
||||
#[cfg(not(feature = "async"))]
|
||||
#[test]
|
||||
fn test_within() {
|
||||
let wm = wm();
|
||||
|
||||
let path = format!("f/tests/delete_me_{}", Uuid::new_v4());
|
||||
let resp = wm
|
||||
.call_api(apis::script_api::create_script(
|
||||
&wm.client_config,
|
||||
&wm.workspace,
|
||||
windmill_api::models::NewScript {
|
||||
path: path.clone(),
|
||||
parent_hash: None,
|
||||
summary: "auto-generated script from rust sdk | testing".into(),
|
||||
description: "auto-generated script from rust sdk | testing".into(),
|
||||
content: r#"//! Add dependencies in the following partial Cargo.toml manifest
|
||||
//!
|
||||
//! ```cargo
|
||||
//! [dependencies]
|
||||
//! anyhow = "1.0.86"
|
||||
//! rand = "0.7.2"
|
||||
//! wmill = { path = "<CWD>" }
|
||||
//! ```
|
||||
//!
|
||||
//! Note that serde is used by default with the `derive` feature.
|
||||
//! You can still reimport it if you need additional features.
|
||||
|
||||
use anyhow::anyhow;
|
||||
use rand::seq::SliceRandom;
|
||||
use wmill::Windmill;
|
||||
use serde::Serialize;
|
||||
|
||||
fn main() -> anyhow::Result<i32> {
|
||||
let wm = Windmill::default()?;
|
||||
|
||||
// Resources
|
||||
let inp = serde_json::json!({
|
||||
"token": "token",
|
||||
"baseUrl": "url"
|
||||
});
|
||||
|
||||
wm.set_resource(Some(inp.clone()), "f/tests/delete_me_test_matrix", "matrix")?;
|
||||
let out = wm.get_resource_any("f/tests/delete_me_test_matrix")?;
|
||||
assert_eq!(inp, out);
|
||||
|
||||
// States
|
||||
let inp = serde_json::json!({ "foo": 2 });
|
||||
wm.set_state(Some(inp.clone()))?;
|
||||
let out = wm.get_state_any()?;
|
||||
assert_eq!(inp, out);
|
||||
|
||||
// Variables
|
||||
let inp = "Foo".to_owned();
|
||||
wm.set_variable(inp.clone(), "f/tests/my_test_var", false)?;
|
||||
let out = wm.get_variable_raw("f/tests/my_test_var")?;
|
||||
assert_eq!(inp, out);
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
"#
|
||||
.replace(
|
||||
"<CWD>",
|
||||
std::env::current_dir()
|
||||
.expect("Failed to get current directory")
|
||||
.to_str()
|
||||
.expect("Failed to parse current directory"),
|
||||
)
|
||||
.into(),
|
||||
schema: None,
|
||||
is_template: None,
|
||||
lock: None,
|
||||
language: windmill_api::models::ScriptLang::Rust,
|
||||
kind: Some(windmill_api::models::new_script::Kind::Script),
|
||||
tag: Some("rust".into()),
|
||||
draft_only: None,
|
||||
envs: None,
|
||||
concurrent_limit: None,
|
||||
concurrency_time_window_s: None,
|
||||
cache_ttl: None,
|
||||
dedicated_worker: None,
|
||||
ws_error_handler_muted: None,
|
||||
priority: None,
|
||||
restart_unless_cancelled: None,
|
||||
timeout: None,
|
||||
delete_after_use: None,
|
||||
deployment_message: None,
|
||||
concurrency_key: None,
|
||||
visible_to_runner_only: None,
|
||||
no_main_func: None,
|
||||
codebase: None,
|
||||
has_preprocessor: None,
|
||||
on_behalf_of_email: None,
|
||||
},
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
json!(0),
|
||||
wm.run_script_sync(
|
||||
//
|
||||
&resp,
|
||||
true,
|
||||
json!(null),
|
||||
None,
|
||||
None,
|
||||
true,
|
||||
false,
|
||||
)
|
||||
.unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
// ASYNC TESTS
|
||||
#[cfg(feature = "async")]
|
||||
#[tokio::test]
|
||||
async fn simple() {
|
||||
let wm = wm();
|
||||
let path = format!("f/tests/delete_me_{}", Uuid::new_v4());
|
||||
|
||||
// Create new
|
||||
wm.set_variable(
|
||||
":0".into(),
|
||||
&path,
|
||||
// TODO: Test with true
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let resp = wm
|
||||
.call_api(apis::script_api::create_script(
|
||||
&wm.client_config,
|
||||
&wm.workspace,
|
||||
windmill_api::models::NewScript {
|
||||
path: path.clone(),
|
||||
parent_hash: None,
|
||||
summary: "auto-generated script from rust sdk | testing".into(),
|
||||
description: "auto-generated script from rust sdk | testing".into(),
|
||||
content: r#"fn main() -> Result<String, String> { Ok("Hello World!".to_owned()) }"#
|
||||
.into(),
|
||||
schema: None,
|
||||
is_template: None,
|
||||
lock: None,
|
||||
language: windmill_api::models::ScriptLang::Rust,
|
||||
kind: Some(windmill_api::models::new_script::Kind::Script),
|
||||
tag: Some("rust".into()),
|
||||
draft_only: None,
|
||||
envs: None,
|
||||
concurrent_limit: None,
|
||||
concurrency_time_window_s: None,
|
||||
cache_ttl: None,
|
||||
dedicated_worker: None,
|
||||
ws_error_handler_muted: None,
|
||||
priority: None,
|
||||
restart_unless_cancelled: None,
|
||||
timeout: None,
|
||||
delete_after_use: None,
|
||||
deployment_message: None,
|
||||
concurrency_key: None,
|
||||
visible_to_runner_only: None,
|
||||
no_main_func: None,
|
||||
codebase: None,
|
||||
has_preprocessor: None,
|
||||
on_behalf_of_email: None,
|
||||
},
|
||||
))
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
json!("Hello World!"),
|
||||
wm.run_script_sync(
|
||||
//
|
||||
&resp,
|
||||
true,
|
||||
json!(null),
|
||||
None,
|
||||
None,
|
||||
true,
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user