mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-20 00:02:19 +00:00
fix: windmill_status_code script now properly return + script bash default arg
This commit is contained in:
@@ -24,7 +24,7 @@ jobs:
|
||||
DATABASE_URL: postgres://postgres:changeme@postgres:5432/windmill
|
||||
LICENSE_KEY: ${{ secrets.WM_LICENSE_KEY_CI }}
|
||||
WORKER_GROUP: main
|
||||
WORKER_TAGS: deno,bun,go,python3,bash,dependency,flow
|
||||
WORKER_TAGS: deno,bun,go,python3,bash,dependency,flow,nativets
|
||||
options: >-
|
||||
--pull always --health-interval 10s --health-timeout 5s
|
||||
--health-retries 5 --health-cmd "curl
|
||||
|
||||
@@ -57,7 +57,7 @@ fn parse_bash_file(code: &str) -> anyhow::Result<Option<Vec<Arg>>> {
|
||||
typ: Typ::Str(None),
|
||||
default: default.clone().map(|x| json!(x)),
|
||||
otyp: None,
|
||||
has_default: false,
|
||||
has_default: default.is_some(),
|
||||
});
|
||||
} else {
|
||||
break;
|
||||
@@ -113,6 +113,8 @@ token="$1"
|
||||
image="$2"
|
||||
digest="${3:-latest with spaces}"
|
||||
text="$4" # with comment
|
||||
non_required="${5:-}"
|
||||
|
||||
|
||||
"#;
|
||||
//println!("{}", serde_json::to_string()?);
|
||||
@@ -141,7 +143,7 @@ text="$4" # with comment
|
||||
name: "digest".to_string(),
|
||||
typ: Typ::Str(None),
|
||||
default: Some(json!("latest with spaces")),
|
||||
has_default: false
|
||||
has_default: true
|
||||
},
|
||||
Arg {
|
||||
otyp: None,
|
||||
@@ -149,6 +151,13 @@ text="$4" # with comment
|
||||
typ: Typ::Str(None),
|
||||
default: None,
|
||||
has_default: false
|
||||
},
|
||||
Arg {
|
||||
otyp: None,
|
||||
name: "non_required".to_string(),
|
||||
typ: Typ::Str(None),
|
||||
default: Some(json!("")),
|
||||
has_default: true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"collaborators": [
|
||||
"Ruben Fiszel <ruben@windmill.dev>"
|
||||
],
|
||||
"version": "1.180.0",
|
||||
"version": "1.186.0",
|
||||
"files": [
|
||||
"windmill_parser_wasm_bg.wasm",
|
||||
"windmill_parser_wasm.js",
|
||||
|
||||
@@ -97,15 +97,6 @@ function getInt32Memory0() {
|
||||
return cachedInt32Memory0;
|
||||
}
|
||||
|
||||
const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } );
|
||||
|
||||
if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); };
|
||||
|
||||
function getStringFromWasm0(ptr, len) {
|
||||
ptr = ptr >>> 0;
|
||||
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
|
||||
}
|
||||
|
||||
function addHeapObject(obj) {
|
||||
if (heap_next === heap.length) heap.push(heap.length + 1);
|
||||
const idx = heap_next;
|
||||
@@ -124,6 +115,15 @@ function getFloat64Memory0() {
|
||||
return cachedFloat64Memory0;
|
||||
}
|
||||
|
||||
const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } );
|
||||
|
||||
if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); };
|
||||
|
||||
function getStringFromWasm0(ptr, len) {
|
||||
ptr = ptr >>> 0;
|
||||
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
|
||||
}
|
||||
|
||||
let cachedBigInt64Memory0 = null;
|
||||
|
||||
function getBigInt64Memory0() {
|
||||
@@ -495,7 +495,7 @@ function __wbg_get_imports() {
|
||||
imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
|
||||
takeObject(arg0);
|
||||
};
|
||||
imports.wbg.__wbg_eval_2e5c54091872c19c = function(arg0, arg1) {
|
||||
imports.wbg.__wbg_eval_4cf9c172060c8b3d = function(arg0, arg1) {
|
||||
const ret = eval(getStringFromWasm0(arg0, arg1));
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
@@ -507,10 +507,6 @@ function __wbg_get_imports() {
|
||||
getInt32Memory0()[arg0 / 4 + 1] = len1;
|
||||
getInt32Memory0()[arg0 / 4 + 0] = ptr1;
|
||||
};
|
||||
imports.wbg.__wbindgen_error_new = function(arg0, arg1) {
|
||||
const ret = new Error(getStringFromWasm0(arg0, arg1));
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_boolean_get = function(arg0) {
|
||||
const v = getObject(arg0);
|
||||
const ret = typeof(v) === 'boolean' ? (v ? 1 : 0) : 2;
|
||||
@@ -528,6 +524,10 @@ function __wbg_get_imports() {
|
||||
const ret = getObject(arg0) === getObject(arg1);
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbindgen_bigint_from_u64 = function(arg0) {
|
||||
const ret = BigInt.asUintN(64, arg0);
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_number_get = function(arg0, arg1) {
|
||||
const obj = getObject(arg1);
|
||||
const ret = typeof(obj) === 'number' ? obj : undefined;
|
||||
@@ -543,8 +543,8 @@ function __wbg_get_imports() {
|
||||
const ret = getObject(arg0) in getObject(arg1);
|
||||
return ret;
|
||||
};
|
||||
imports.wbg.__wbindgen_bigint_from_u64 = function(arg0) {
|
||||
const ret = BigInt.asUintN(64, arg0);
|
||||
imports.wbg.__wbindgen_error_new = function(arg0, arg1) {
|
||||
const ret = new Error(getStringFromWasm0(arg0, arg1));
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
imports.wbg.__wbindgen_jsval_loose_eq = function(arg0, arg1) {
|
||||
|
||||
Binary file not shown.
@@ -1757,12 +1757,17 @@ impl Drop for Guard {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct WindmillStatusCode {
|
||||
windmill_status_code: Option<u16>,
|
||||
result: Option<Box<RawValue>>,
|
||||
}
|
||||
async fn run_wait_result<T>(
|
||||
authed: ApiAuthed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
uuid: Uuid,
|
||||
Path((w_id, _)): Path<(String, T)>,
|
||||
) -> error::JsonResult<serde_json::Value> {
|
||||
) -> error::Result<Response> {
|
||||
let mut result;
|
||||
let timeout = SERVER_CONFIG.read().await.timeout_wait_result.clone();
|
||||
let timeout_ms = if timeout <= 0 {
|
||||
@@ -1781,16 +1786,16 @@ async fn run_wait_result<T>(
|
||||
|
||||
let fast_poll_duration = *WAIT_RESULT_FAST_POLL_DURATION_SECS as u64 * 1000;
|
||||
let mut accumulated_delay = 0 as u64;
|
||||
|
||||
loop {
|
||||
let mut tx = user_db.clone().begin(&authed).await?;
|
||||
result = sqlx::query_scalar!(
|
||||
"SELECT result FROM completed_job WHERE id = $1 AND workspace_id = $2",
|
||||
uuid,
|
||||
&w_id
|
||||
)
|
||||
.fetch_optional(&mut *tx)
|
||||
.await?
|
||||
.flatten();
|
||||
result =
|
||||
sqlx::query("SELECT result FROM completed_job WHERE id = $1 AND workspace_id = $2")
|
||||
.bind(uuid)
|
||||
.bind(&w_id)
|
||||
.fetch_optional(&mut *tx)
|
||||
.await?;
|
||||
|
||||
drop(tx);
|
||||
|
||||
if result.is_some() {
|
||||
@@ -1810,14 +1815,18 @@ async fn run_wait_result<T>(
|
||||
}
|
||||
if let Some(result) = result {
|
||||
g.done = true;
|
||||
let status_code = result
|
||||
.get("windmill_status_code")
|
||||
.and_then(|x| x.as_i64())
|
||||
.and_then(|x| StatusCode::from_u16(x as u16).ok());
|
||||
if let Some(status_code) = status_code {
|
||||
return Err(Error::CustomStatusCode(status_code, result));
|
||||
let result = RawResult::from_row(&result)?.result;
|
||||
|
||||
let status_code = serde_json::from_str::<WindmillStatusCode>(result.get());
|
||||
match status_code {
|
||||
Ok(WindmillStatusCode { windmill_status_code: Some(status_code), result }) => {
|
||||
Err(Error::CustomStatusCode(
|
||||
StatusCode::from_u16(status_code).unwrap_or_else(|_| StatusCode::IM_A_TEAPOT),
|
||||
result,
|
||||
))
|
||||
}
|
||||
_ => Ok(Json(result).into_response()),
|
||||
}
|
||||
Ok(Json(result))
|
||||
} else {
|
||||
Err(Error::ExecutionErr(format!("timeout after {}s", timeout)))
|
||||
}
|
||||
@@ -1870,12 +1879,12 @@ pub async fn run_wait_result_job_by_path_get(
|
||||
Extension(db): Extension<DB>,
|
||||
Path((w_id, script_path)): Path<(String, StripPath)>,
|
||||
Query(run_query): Query<RunJobQuery>,
|
||||
) -> error::JsonResult<serde_json::Value> {
|
||||
) -> error::Result<Response> {
|
||||
#[cfg(feature = "enterprise")]
|
||||
check_license_key_valid().await?;
|
||||
|
||||
if method == http::Method::HEAD {
|
||||
return Ok(Json(serde_json::json!("")));
|
||||
return Ok(Json(serde_json::json!("")).into_response());
|
||||
}
|
||||
let payload_r = run_query
|
||||
.payload
|
||||
@@ -1935,12 +1944,12 @@ pub async fn run_wait_result_flow_by_path_get(
|
||||
Path((w_id, flow_path)): Path<(String, StripPath)>,
|
||||
|
||||
Query(run_query): Query<RunJobQuery>,
|
||||
) -> error::JsonResult<serde_json::Value> {
|
||||
) -> error::Result<Response> {
|
||||
#[cfg(feature = "enterprise")]
|
||||
check_license_key_valid().await?;
|
||||
|
||||
if method == http::Method::HEAD {
|
||||
return Ok(Json(serde_json::json!("")));
|
||||
return Ok(Json(serde_json::json!("")).into_response());
|
||||
}
|
||||
let payload_r = run_query
|
||||
.payload
|
||||
@@ -1970,7 +1979,7 @@ pub async fn run_wait_result_script_by_path(
|
||||
Path((w_id, script_path)): Path<(String, StripPath)>,
|
||||
Query(run_query): Query<RunJobQuery>,
|
||||
args: PushArgs<HashMap<String, Box<JsonRawValue>>>,
|
||||
) -> error::JsonResult<serde_json::Value> {
|
||||
) -> error::Result<Response> {
|
||||
#[cfg(feature = "enterprise")]
|
||||
check_license_key_valid().await?;
|
||||
|
||||
@@ -1996,7 +2005,7 @@ async fn run_wait_result_script_by_path_internal(
|
||||
user_db: UserDB,
|
||||
w_id: String,
|
||||
args: PushArgs<HashMap<String, Box<JsonRawValue>>>,
|
||||
) -> Result<Json<serde_json::Value>, Error> {
|
||||
) -> error::Result<Response> {
|
||||
check_queue_too_long(&db, QUEUE_LIMIT_WAIT_RESULT.or(run_query.queue_limit)).await?;
|
||||
let script_path = script_path.to_path();
|
||||
check_scopes(&authed, || format!("run:script/{script_path}"))?;
|
||||
@@ -2042,7 +2051,7 @@ pub async fn run_wait_result_script_by_hash(
|
||||
Path((w_id, script_hash)): Path<(String, ScriptHash)>,
|
||||
Query(run_query): Query<RunJobQuery>,
|
||||
args: PushArgs<HashMap<String, Box<JsonRawValue>>>,
|
||||
) -> error::JsonResult<serde_json::Value> {
|
||||
) -> error::Result<Response> {
|
||||
#[cfg(feature = "enterprise")]
|
||||
check_license_key_valid().await?;
|
||||
|
||||
@@ -2107,7 +2116,7 @@ pub async fn run_wait_result_flow_by_path(
|
||||
Path((w_id, flow_path)): Path<(String, StripPath)>,
|
||||
Query(run_query): Query<RunJobQuery>,
|
||||
args: PushArgs<HashMap<String, Box<JsonRawValue>>>,
|
||||
) -> error::JsonResult<serde_json::Value> {
|
||||
) -> error::Result<Response> {
|
||||
#[cfg(feature = "enterprise")]
|
||||
check_license_key_valid().await?;
|
||||
|
||||
@@ -2126,7 +2135,7 @@ async fn run_wait_result_flow_by_path_internal(
|
||||
user_db: UserDB,
|
||||
args: PushArgs<HashMap<String, Box<JsonRawValue>>>,
|
||||
w_id: String,
|
||||
) -> Result<Json<serde_json::Value>, Error> {
|
||||
) -> error::Result<Response> {
|
||||
check_queue_too_long(&db, run_query.queue_limit).await?;
|
||||
|
||||
let flow_path = flow_path.to_path();
|
||||
|
||||
@@ -15,6 +15,7 @@ use axum::{
|
||||
};
|
||||
|
||||
use hyper::StatusCode;
|
||||
use serde_json::value::RawValue;
|
||||
#[cfg(feature = "sqlx")]
|
||||
use sqlx::migrate::MigrateError;
|
||||
use thiserror::Error;
|
||||
@@ -65,7 +66,7 @@ pub enum Error {
|
||||
#[error("Error: {0:#?}")]
|
||||
JsonErr(serde_json::Value),
|
||||
#[error("Custom Status Code: {0:#?}")]
|
||||
CustomStatusCode(StatusCode, serde_json::Value),
|
||||
CustomStatusCode(StatusCode, Option<Box<RawValue>>),
|
||||
#[error("{0}")]
|
||||
OpenAIError(String),
|
||||
}
|
||||
@@ -84,30 +85,41 @@ pub fn to_anyhow<T: 'static + std::error::Error + Send + Sync>(e: T) -> anyhow::
|
||||
#[cfg(feature = "axum")]
|
||||
impl IntoResponse for Error {
|
||||
fn into_response(self) -> axum::response::Response<BoxBody> {
|
||||
let e = &self;
|
||||
let body = body::boxed(body::Full::from(e.to_string()));
|
||||
let status = match self {
|
||||
Self::NotFound(_) => axum::http::StatusCode::NOT_FOUND,
|
||||
Self::NotAuthorized(_) => axum::http::StatusCode::UNAUTHORIZED,
|
||||
Self::RequireAdmin(_) => axum::http::StatusCode::FORBIDDEN,
|
||||
Self::CustomStatusCode(code, _) => code,
|
||||
Self::SqlErr(_) | Self::BadRequest(_) | Self::OpenAIError(_) => {
|
||||
axum::http::StatusCode::BAD_REQUEST
|
||||
match self {
|
||||
Self::CustomStatusCode(code, result) => {
|
||||
let mut res = Json(result).into_response();
|
||||
let status_mut = res.status_mut();
|
||||
*status_mut = code;
|
||||
res
|
||||
}
|
||||
_ => axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
};
|
||||
_ => {
|
||||
let e = &self;
|
||||
let body = body::boxed(body::Full::from(e.to_string()));
|
||||
|
||||
if matches!(status, axum::http::StatusCode::NOT_FOUND) {
|
||||
tracing::warn!(not_found = e.to_string());
|
||||
} else {
|
||||
tracing::error!(error = e.to_string());
|
||||
};
|
||||
let status = match self {
|
||||
Self::NotFound(_) => axum::http::StatusCode::NOT_FOUND,
|
||||
Self::NotAuthorized(_) => axum::http::StatusCode::UNAUTHORIZED,
|
||||
Self::RequireAdmin(_) => axum::http::StatusCode::FORBIDDEN,
|
||||
Self::CustomStatusCode(code, _) => code,
|
||||
Self::SqlErr(_) | Self::BadRequest(_) | Self::OpenAIError(_) => {
|
||||
axum::http::StatusCode::BAD_REQUEST
|
||||
}
|
||||
_ => axum::http::StatusCode::INTERNAL_SERVER_ERROR,
|
||||
};
|
||||
|
||||
axum::response::Response::builder()
|
||||
.header("Content-Type", "text/plain")
|
||||
.status(status)
|
||||
.body(body)
|
||||
.unwrap()
|
||||
if matches!(status, axum::http::StatusCode::NOT_FOUND) {
|
||||
tracing::warn!(not_found = e.to_string());
|
||||
} else {
|
||||
tracing::error!(error = e.to_string());
|
||||
};
|
||||
|
||||
axum::response::Response::builder()
|
||||
.header("Content-Type", "text/plain")
|
||||
.status(status)
|
||||
.body(body)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Generated
+7
-7
@@ -47,7 +47,7 @@
|
||||
"svelte-tiny-virtual-list": "^2.0.5",
|
||||
"tailwind-merge": "^1.13.2",
|
||||
"vscode-ws-jsonrpc": "3.0.0",
|
||||
"windmill-parser-wasm": "^1.180.0",
|
||||
"windmill-parser-wasm": "^1.186.0",
|
||||
"y-monaco": "^0.1.4",
|
||||
"y-websocket": "^1.5.0",
|
||||
"yjs": "^13.6.7"
|
||||
@@ -9946,9 +9946,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/windmill-parser-wasm": {
|
||||
"version": "1.180.0",
|
||||
"resolved": "https://registry.npmjs.org/windmill-parser-wasm/-/windmill-parser-wasm-1.180.0.tgz",
|
||||
"integrity": "sha512-ikkyfiAdILGUZT0g+eiZ9dgPYFHCjtZVFCRUAkw7PlbK+8bT6ROa+mv1ZRxkc3LZLGsWEwteojdcjfopPFTTAQ=="
|
||||
"version": "1.186.0",
|
||||
"resolved": "https://registry.npmjs.org/windmill-parser-wasm/-/windmill-parser-wasm-1.186.0.tgz",
|
||||
"integrity": "sha512-xoeGloTQHl54WWp97rmy94Us6bzY4ckU+Y7+f4NcR4l9DG9XpzsHQrjwzZH1Ak9zM91oIQDdgTBZkrAsZ5N97w=="
|
||||
},
|
||||
"node_modules/wordwrap": {
|
||||
"version": "1.0.0",
|
||||
@@ -17012,9 +17012,9 @@
|
||||
}
|
||||
},
|
||||
"windmill-parser-wasm": {
|
||||
"version": "1.180.0",
|
||||
"resolved": "https://registry.npmjs.org/windmill-parser-wasm/-/windmill-parser-wasm-1.180.0.tgz",
|
||||
"integrity": "sha512-ikkyfiAdILGUZT0g+eiZ9dgPYFHCjtZVFCRUAkw7PlbK+8bT6ROa+mv1ZRxkc3LZLGsWEwteojdcjfopPFTTAQ=="
|
||||
"version": "1.186.0",
|
||||
"resolved": "https://registry.npmjs.org/windmill-parser-wasm/-/windmill-parser-wasm-1.186.0.tgz",
|
||||
"integrity": "sha512-xoeGloTQHl54WWp97rmy94Us6bzY4ckU+Y7+f4NcR4l9DG9XpzsHQrjwzZH1Ak9zM91oIQDdgTBZkrAsZ5N97w=="
|
||||
},
|
||||
"wordwrap": {
|
||||
"version": "1.0.0",
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
"svelte-tiny-virtual-list": "^2.0.5",
|
||||
"tailwind-merge": "^1.13.2",
|
||||
"vscode-ws-jsonrpc": "3.0.0",
|
||||
"windmill-parser-wasm": "^1.180.0",
|
||||
"windmill-parser-wasm": "^1.186.0",
|
||||
"y-monaco": "^0.1.4",
|
||||
"y-websocket": "^1.5.0",
|
||||
"yjs": "^13.6.7"
|
||||
|
||||
Reference in New Issue
Block a user