mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-08 08:04:25 +00:00
feat: add native powershell support (#2025)
* feat: add powershell support * fix: lang build
This commit is contained in:
@@ -0,0 +1 @@
|
||||
-- Add down migration script here
|
||||
@@ -0,0 +1,2 @@
|
||||
-- Add up migration script here
|
||||
ALTER TYPE SCRIPT_LANG ADD VALUE IF NOT EXISTS 'powershell';
|
||||
@@ -8,7 +8,7 @@ use std::collections::HashMap;
|
||||
use windmill_parser::{Arg, MainArgSignature, Typ};
|
||||
|
||||
pub fn parse_bash_sig(code: &str) -> anyhow::Result<MainArgSignature> {
|
||||
let parsed = parse_file(&code)?;
|
||||
let parsed = parse_bash_file(&code)?;
|
||||
if let Some(x) = parsed {
|
||||
let args = x;
|
||||
Ok(MainArgSignature { star_args: false, star_kwargs: false, args })
|
||||
@@ -17,13 +17,26 @@ pub fn parse_bash_sig(code: &str) -> anyhow::Result<MainArgSignature> {
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref RE: Regex = Regex::new(r#"(?m)^(\w+)="\$(?:(\d+)|\{(\d+):-(.*)\})"(?:([\t ]*#.*)?)$"#).unwrap();
|
||||
pub fn parse_powershell_sig(code: &str) -> anyhow::Result<MainArgSignature> {
|
||||
let parsed = parse_powershell_file(&code)?;
|
||||
if let Some(x) = parsed {
|
||||
let args = x;
|
||||
Ok(MainArgSignature { star_args: false, star_kwargs: false, args })
|
||||
} else {
|
||||
Err(anyhow!("Error parsing powershell script".to_string()))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_file(code: &str) -> anyhow::Result<Option<Vec<Arg>>> {
|
||||
lazy_static::lazy_static! {
|
||||
static ref RE_BASH: Regex = Regex::new(r#"(?m)^(\w+)="\$(?:(\d+)|\{(\d+):-(.*)\})"(?:[\t ]*)?(?:#.*)?$"#).unwrap();
|
||||
|
||||
static ref RE_POWERSHELL_PARAM: Regex = Regex::new(r#"(?m)param[\t ]*\(([^)]*)\)"#).unwrap();
|
||||
static ref RE_POWERSHELL_ARGS: Regex = Regex::new(r#"(?:\[(\w+)\])?\$(\w+)[\t ]*(?:=[\t ]*(?:(?:(?:"|')([^"\n\r\$]*)(?:"|'))|([\d.]+)))?"#).unwrap();
|
||||
}
|
||||
|
||||
fn parse_bash_file(code: &str) -> anyhow::Result<Option<Vec<Arg>>> {
|
||||
let mut hm: HashMap<i32, (String, Option<String>)> = HashMap::new();
|
||||
for cap in RE.captures_iter(code) {
|
||||
for cap in RE_BASH.captures_iter(code) {
|
||||
hm.insert(
|
||||
cap.get(2)
|
||||
.or(cap.get(3))
|
||||
@@ -53,6 +66,39 @@ fn parse_file(code: &str) -> anyhow::Result<Option<Vec<Arg>>> {
|
||||
Ok(Some(args))
|
||||
}
|
||||
|
||||
fn parse_powershell_file(code: &str) -> anyhow::Result<Option<Vec<Arg>>> {
|
||||
let param_wrapper = RE_POWERSHELL_PARAM.captures(code);
|
||||
let mut args = vec![];
|
||||
if let Some(param_wrapper) = param_wrapper {
|
||||
let param_wrapper = param_wrapper.get(1).unwrap().as_str();
|
||||
for cap in RE_POWERSHELL_ARGS.captures_iter(param_wrapper) {
|
||||
let typ = cap
|
||||
.get(1)
|
||||
.map(|x| x.as_str().to_string())
|
||||
.unwrap_or("string".to_string());
|
||||
let name = cap.get(2).unwrap().as_str().to_string();
|
||||
let default = cap
|
||||
.get(3)
|
||||
.or(cap.get(4))
|
||||
.map(|x| json!(x.as_str().to_string()));
|
||||
|
||||
args.push(Arg {
|
||||
name: name,
|
||||
typ: match typ.as_str() {
|
||||
"string" => Typ::Str(None),
|
||||
"int" | "long" => Typ::Int,
|
||||
"decimal" | "double" | "single" => Typ::Float,
|
||||
_ => Typ::Str(None),
|
||||
},
|
||||
default: default.clone(),
|
||||
otyp: None,
|
||||
has_default: default.is_some(),
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok(Some(args))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ pub fn parse_graphql_sig(code: &str) -> anyhow::Result<MainArgSignature> {
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref RE_ARG_GRAPHQL: Regex = Regex::new(r#"\$(\w+)\s*:\s*(?:(\w+)!?|\[(\w+)!?\])!?\s*(?:=\s*(\w+)\s*)?"#).unwrap();
|
||||
static ref RE_ARG_GRAPHQL_ARRAY: Regex = Regex::new(r#"^\[(\w+)!?\]!?$"#).unwrap();
|
||||
}
|
||||
|
||||
fn parse_graphql_file(code: &str) -> anyhow::Result<Option<Vec<Arg>>> {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"collaborators": [
|
||||
"Ruben Fiszel <ruben@windmill.dev>"
|
||||
],
|
||||
"version": "1.141.0",
|
||||
"version": "1.143.0",
|
||||
"files": [
|
||||
"windmill_parser_wasm_bg.wasm",
|
||||
"windmill_parser_wasm.js",
|
||||
|
||||
@@ -14,6 +14,11 @@ export function parse_bash(code: string): string;
|
||||
* @param {string} code
|
||||
* @returns {string}
|
||||
*/
|
||||
export function parse_powershell(code: string): string;
|
||||
/**
|
||||
* @param {string} code
|
||||
* @returns {string}
|
||||
*/
|
||||
export function parse_go(code: string): string;
|
||||
/**
|
||||
* @param {string} code
|
||||
@@ -52,6 +57,7 @@ export interface InitOutput {
|
||||
readonly memory: WebAssembly.Memory;
|
||||
readonly parse_deno: (a: number, b: number, c: number) => void;
|
||||
readonly parse_bash: (a: number, b: number, c: number) => void;
|
||||
readonly parse_powershell: (a: number, b: number, c: number) => void;
|
||||
readonly parse_go: (a: number, b: number, c: number) => void;
|
||||
readonly parse_python: (a: number, b: number, c: number) => void;
|
||||
readonly parse_sql: (a: number, b: number, c: number) => void;
|
||||
|
||||
@@ -243,6 +243,29 @@ export function parse_bash(code) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} code
|
||||
* @returns {string}
|
||||
*/
|
||||
export function parse_powershell(code) {
|
||||
let deferred2_0;
|
||||
let deferred2_1;
|
||||
try {
|
||||
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
|
||||
const ptr0 = passStringToWasm0(code, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
const len0 = WASM_VECTOR_LEN;
|
||||
wasm.parse_powershell(retptr, ptr0, len0);
|
||||
var r0 = getInt32Memory0()[retptr / 4 + 0];
|
||||
var r1 = getInt32Memory0()[retptr / 4 + 1];
|
||||
deferred2_0 = r0;
|
||||
deferred2_1 = r1;
|
||||
return getStringFromWasm0(r0, r1);
|
||||
} finally {
|
||||
wasm.__wbindgen_add_to_stack_pointer(16);
|
||||
wasm.__wbindgen_free(deferred2_0, deferred2_1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} code
|
||||
* @returns {string}
|
||||
@@ -446,7 +469,7 @@ async function __wbg_load(module, imports) {
|
||||
function __wbg_get_imports() {
|
||||
const imports = {};
|
||||
imports.wbg = {};
|
||||
imports.wbg.__wbg_eval_9331e2bd3095f3d6 = function(arg0, arg1) {
|
||||
imports.wbg.__wbg_eval_44bde4e76596166e = function(arg0, arg1) {
|
||||
const ret = eval(getStringFromWasm0(arg0, arg1));
|
||||
return addHeapObject(ret);
|
||||
};
|
||||
|
||||
Binary file not shown.
@@ -3,6 +3,7 @@
|
||||
export const memory: WebAssembly.Memory;
|
||||
export function parse_deno(a: number, b: number, c: number): void;
|
||||
export function parse_bash(a: number, b: number, c: number): void;
|
||||
export function parse_powershell(a: number, b: number, c: number): void;
|
||||
export function parse_go(a: number, b: number, c: number): void;
|
||||
export function parse_python(a: number, b: number, c: number): void;
|
||||
export function parse_sql(a: number, b: number, c: number): void;
|
||||
|
||||
@@ -20,6 +20,11 @@ pub fn parse_bash(code: &str) -> String {
|
||||
wrap_sig(windmill_parser_bash::parse_bash_sig(code))
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn parse_powershell(code: &str) -> String {
|
||||
wrap_sig(windmill_parser_bash::parse_powershell_sig(code))
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn parse_go(code: &str) -> String {
|
||||
wrap_sig(windmill_parser_go::parse_go_sig(code))
|
||||
|
||||
@@ -5691,6 +5691,7 @@ components:
|
||||
deno,
|
||||
go,
|
||||
bash,
|
||||
powershell,
|
||||
postgresql,
|
||||
mysql,
|
||||
bigquery,
|
||||
@@ -5768,6 +5769,7 @@ components:
|
||||
deno,
|
||||
go,
|
||||
bash,
|
||||
powershell,
|
||||
postgresql,
|
||||
mysql,
|
||||
bigquery,
|
||||
@@ -5950,6 +5952,7 @@ components:
|
||||
deno,
|
||||
go,
|
||||
bash,
|
||||
powershell,
|
||||
postgresql,
|
||||
mysql,
|
||||
bigquery,
|
||||
@@ -6052,6 +6055,7 @@ components:
|
||||
deno,
|
||||
go,
|
||||
bash,
|
||||
powershell,
|
||||
postgresql,
|
||||
mysql,
|
||||
bigquery,
|
||||
@@ -6563,6 +6567,7 @@ components:
|
||||
deno,
|
||||
go,
|
||||
bash,
|
||||
powershell,
|
||||
postgresql,
|
||||
mysql,
|
||||
bigquery,
|
||||
|
||||
@@ -1474,6 +1474,7 @@ async fn tarball_workspace(
|
||||
ScriptLang::Deno => "ts",
|
||||
ScriptLang::Go => "go",
|
||||
ScriptLang::Bash => "sh",
|
||||
ScriptLang::Powershell => "ps1",
|
||||
ScriptLang::Postgresql => "pg.sql",
|
||||
ScriptLang::Mysql => "my.sql",
|
||||
ScriptLang::Bigquery => "bq.sql",
|
||||
|
||||
@@ -30,6 +30,7 @@ pub enum ScriptLang {
|
||||
Python3,
|
||||
Go,
|
||||
Bash,
|
||||
Powershell,
|
||||
Postgresql,
|
||||
Bun,
|
||||
Mysql,
|
||||
@@ -47,6 +48,7 @@ impl ScriptLang {
|
||||
ScriptLang::Python3 => "python3",
|
||||
ScriptLang::Go => "go",
|
||||
ScriptLang::Bash => "bash",
|
||||
ScriptLang::Powershell => "powershell",
|
||||
ScriptLang::Postgresql => "postgresql",
|
||||
ScriptLang::Mysql => "mysql",
|
||||
ScriptLang::Bigquery => "bigquery",
|
||||
|
||||
@@ -69,6 +69,7 @@ lazy_static::lazy_static! {
|
||||
"python3".to_string(),
|
||||
"go".to_string(),
|
||||
"bash".to_string(),
|
||||
"powershell".to_string(),
|
||||
"nativets".to_string(),
|
||||
"mysql".to_string(),
|
||||
"graphql".to_string(),
|
||||
|
||||
@@ -356,6 +356,7 @@ pub async fn run_worker<R: rsmq_async::RsmqConnection + Send + Sync + Clone + 's
|
||||
Some(ScriptLang::Deno),
|
||||
Some(ScriptLang::Go),
|
||||
Some(ScriptLang::Bash),
|
||||
Some(ScriptLang::Powershell),
|
||||
Some(ScriptLang::Nativets),
|
||||
Some(ScriptLang::Postgresql),
|
||||
Some(ScriptLang::Mysql),
|
||||
@@ -1509,6 +1510,21 @@ mount {{
|
||||
)
|
||||
.await
|
||||
},
|
||||
Some(ScriptLang::Powershell) => {
|
||||
handle_powershell_job(
|
||||
logs,
|
||||
job,
|
||||
db,
|
||||
client,
|
||||
&inner_content,
|
||||
job_dir,
|
||||
&shared_mount,
|
||||
base_internal_url,
|
||||
worker_name,
|
||||
envs
|
||||
)
|
||||
.await
|
||||
}
|
||||
_ => panic!("unreachable, language is not supported: {language:#?}"),
|
||||
};
|
||||
tracing::info!(
|
||||
@@ -1611,6 +1627,92 @@ async fn handle_bash_job(
|
||||
.unwrap_or_else(String::new)))
|
||||
}
|
||||
|
||||
|
||||
#[tracing::instrument(level = "trace", skip_all)]
|
||||
async fn handle_powershell_job(
|
||||
logs: &mut String,
|
||||
job: &QueuedJob,
|
||||
db: &sqlx::Pool<sqlx::Postgres>,
|
||||
client: &AuthedClientBackgroundTask,
|
||||
content: &str,
|
||||
job_dir: &str,
|
||||
shared_mount: &str,
|
||||
base_internal_url: &str,
|
||||
worker_name: &str,
|
||||
envs: HashMap<String, String>,
|
||||
) -> Result<serde_json::Value, Error> {
|
||||
logs.push_str("\n\n--- POWERSHELL CODE EXECUTION ---\n");
|
||||
set_logs(logs, &job.id, db).await;
|
||||
let hm: serde_json::Map<String, Value> = match job.args {
|
||||
Some(Value::Object(ref hm)) => hm.clone(),
|
||||
_ => serde_json::Map::new(),
|
||||
};
|
||||
|
||||
let args_owned = windmill_parser_bash::parse_powershell_sig(&content)?
|
||||
.args
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
(arg.name.clone(), hm.get(&arg.name)
|
||||
.and_then(|v| match v {
|
||||
Value::String(s) => Some(s.clone()),
|
||||
_ => serde_json::to_string(v).ok(),
|
||||
})
|
||||
.unwrap_or_else(String::new))
|
||||
})
|
||||
.collect::<Vec<(String, String)>>();
|
||||
let pwsh_args = args_owned.iter().map(|(n, v)| format!("--{n} {v}")).join(" ");
|
||||
|
||||
let content = content.replace('$', r"\$"); // escape powershell variables
|
||||
write_file(job_dir, "main.sh", &format!("set -e\ncat > script.ps1 << EOF\n{content}\nEOF\npwsh -File script.ps1 {pwsh_args}\necho \"\"\nsleep 0.02")).await?;
|
||||
let token = client.get_token().await;
|
||||
let mut reserved_variables = get_reserved_variables(job, &token, db).await?;
|
||||
reserved_variables.insert("RUST_LOG".to_string(), "info".to_string());
|
||||
|
||||
let child = if !*DISABLE_NSJAIL {
|
||||
let _ = write_file(
|
||||
job_dir,
|
||||
"run.config.proto",
|
||||
&NSJAIL_CONFIG_RUN_BASH_CONTENT
|
||||
.replace("{JOB_DIR}", job_dir)
|
||||
.replace("{CLONE_NEWUSER}", &(!*DISABLE_NUSER).to_string())
|
||||
.replace("{SHARED_MOUNT}", shared_mount),
|
||||
)
|
||||
.await?;
|
||||
let cmd_args = vec!["--config", "run.config.proto", "--", "/bin/bash", "main.sh"];
|
||||
Command::new(NSJAIL_PATH.as_str())
|
||||
.current_dir(job_dir)
|
||||
.env_clear()
|
||||
.envs(reserved_variables)
|
||||
.env("PATH", PATH_ENV.as_str())
|
||||
.env("BASE_INTERNAL_URL", base_internal_url)
|
||||
.args(cmd_args)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()?
|
||||
} else {
|
||||
let cmd_args = vec!["main.sh"];
|
||||
Command::new("/bin/bash")
|
||||
.current_dir(job_dir)
|
||||
.env_clear()
|
||||
.envs(envs)
|
||||
.envs(reserved_variables)
|
||||
.env("PATH", PATH_ENV.as_str())
|
||||
.env("BASE_INTERNAL_URL", base_internal_url)
|
||||
.env("HOME", HOME_ENV.as_str())
|
||||
.args(cmd_args)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()?
|
||||
};
|
||||
handle_child(&job.id, db, logs, child, !*DISABLE_NSJAIL, worker_name, &job.workspace_id, "bash run", job.timeout).await?;
|
||||
//for now bash jobs have an empty result object
|
||||
Ok(serde_json::json!(logs
|
||||
.lines()
|
||||
.last()
|
||||
.map(|x| x.to_string())
|
||||
.unwrap_or_else(String::new)))
|
||||
}
|
||||
|
||||
fn get_common_deno_proc_envs(token: &str, base_internal_url: &str) -> HashMap<String, String> {
|
||||
let hostname_base = BASE_URL.split("://").last().unwrap_or("localhost");
|
||||
let hostname_internal = base_internal_url.split("://").last().unwrap_or("localhost");
|
||||
@@ -2250,6 +2352,7 @@ async fn capture_dependency_job(
|
||||
ScriptLang::Snowflake => Ok("".to_owned()),
|
||||
ScriptLang::Graphql => Ok("".to_owned()),
|
||||
ScriptLang::Bash => Ok("".to_owned()),
|
||||
ScriptLang::Powershell => Ok("".to_owned()),
|
||||
ScriptLang::Nativets => Ok("".to_owned()),
|
||||
|
||||
}
|
||||
|
||||
+5
-1
@@ -31,7 +31,9 @@ async function dev(opts: GlobalOptions & { filter?: string }) {
|
||||
path.endsWith(".ts") ||
|
||||
path.endsWith(".py") ||
|
||||
path.endsWith(".sh") ||
|
||||
path.endsWith(".sql")
|
||||
path.endsWith(".sql") ||
|
||||
path.endsWith(".gql") ||
|
||||
path.endsWith(".ps1")
|
||||
);
|
||||
if (paths.length == 0) {
|
||||
return;
|
||||
@@ -56,6 +58,8 @@ async function dev(opts: GlobalOptions & { filter?: string }) {
|
||||
? "go"
|
||||
: ext == "sh"
|
||||
? "bash"
|
||||
: ext == "ps1"
|
||||
? "powershell"
|
||||
: ext == "sql"
|
||||
? splitted.length > 2 && splitted[splitted.length - 2] == "my"
|
||||
? "mysql"
|
||||
|
||||
+58
-17
@@ -72,7 +72,10 @@ export async function handleFile(
|
||||
(path.endsWith(".ts") ||
|
||||
path.endsWith(".py") ||
|
||||
path.endsWith(".go") ||
|
||||
path.endsWith(".sh"))
|
||||
path.endsWith(".sh") ||
|
||||
path.endsWith(".sql") ||
|
||||
path.endsWith(".gql") ||
|
||||
path.endsWith(".ps1"))
|
||||
) {
|
||||
if (alreadySynced.includes(path)) {
|
||||
return true;
|
||||
@@ -181,16 +184,27 @@ export async function findContentFile(filePath: string) {
|
||||
filePath.replace(".script.json", ".py"),
|
||||
filePath.replace(".script.json", ".go"),
|
||||
filePath.replace(".script.json", ".sh"),
|
||||
filePath.replace(".script.json", ".sql"),
|
||||
filePath.replace(".script.json", "pg.sql"),
|
||||
filePath.replace(".script.json", "my.sql"),
|
||||
filePath.replace(".script.json", "bq.sql"),
|
||||
filePath.replace(".script.json", "sf.sql"),
|
||||
filePath.replace(".script.json", ".fetch.ts"),
|
||||
filePath.replace(".script.json", ".bun.ts"),
|
||||
filePath.replace(".script.json", ".gql"),
|
||||
filePath.replace(".script.json", ".ps1"),
|
||||
]
|
||||
: [
|
||||
filePath.replace(".script.yaml", ".ts"),
|
||||
filePath.replace(".script.yaml", ".py"),
|
||||
filePath.replace(".script.yaml", ".go"),
|
||||
filePath.replace(".script.yaml", ".sh"),
|
||||
filePath.replace(".script.yaml", ".sql"),
|
||||
filePath.replace(".script.yaml", "pg.sql"),
|
||||
filePath.replace(".script.yaml", "bq.sql"),
|
||||
filePath.replace(".script.yaml", "sf.sql"),
|
||||
filePath.replace(".script.yaml", ".fetch.ts"),
|
||||
filePath.replace(".script.yaml", ".bun.ts"),
|
||||
filePath.replace(".script.yaml", ".gql"),
|
||||
filePath.replace(".script.yaml", ".ps1"),
|
||||
];
|
||||
const validCandidates = (
|
||||
await Promise.all(
|
||||
@@ -220,21 +234,48 @@ export async function findContentFile(filePath: string) {
|
||||
|
||||
export function inferContentTypeFromFilePath(
|
||||
contentPath: string
|
||||
): "python3" | "deno" | "go" | "bash" {
|
||||
let language = contentPath.substring(contentPath.lastIndexOf("."));
|
||||
if (language == ".ts") language = "deno";
|
||||
if (language == ".py") language = "python3";
|
||||
if (language == ".sh") language = "bash";
|
||||
if (language == ".go") language = "go";
|
||||
if (
|
||||
language != "python3" &&
|
||||
language != "deno" &&
|
||||
language != "go" &&
|
||||
language != "bash"
|
||||
) {
|
||||
throw new Error("Invalid language: " + language);
|
||||
):
|
||||
| "python3"
|
||||
| "deno"
|
||||
| "bun"
|
||||
| "nativets"
|
||||
| "go"
|
||||
| "bash"
|
||||
| "powershell"
|
||||
| "postgresql"
|
||||
| "mysql"
|
||||
| "bigquery"
|
||||
| "snowflake"
|
||||
| "graphql" {
|
||||
if (contentPath.endsWith(".py")) {
|
||||
return "python3";
|
||||
} else if (contentPath.endsWith("fetch.ts")) {
|
||||
return "nativets";
|
||||
} else if (contentPath.endsWith("bun.ts")) {
|
||||
return "bun";
|
||||
} else if (contentPath.endsWith(".ts")) {
|
||||
return "deno";
|
||||
} else if (contentPath.endsWith(".go")) {
|
||||
return "go";
|
||||
} else if (contentPath.endsWith(".my.sql")) {
|
||||
return "mysql";
|
||||
} else if (contentPath.endsWith(".bq.sql")) {
|
||||
return "bigquery";
|
||||
} else if (contentPath.endsWith(".sf.sql")) {
|
||||
return "snowflake";
|
||||
} else if (contentPath.endsWith(".pg.sql")) {
|
||||
return "postgresql";
|
||||
} else if (contentPath.endsWith(".gql")) {
|
||||
return "graphql";
|
||||
} else if (contentPath.endsWith(".sh")) {
|
||||
return "bash";
|
||||
} else if (contentPath.endsWith(".ps1")) {
|
||||
return "powershell";
|
||||
} else {
|
||||
throw new Error(
|
||||
"Invalid language: " + contentPath.substring(contentPath.lastIndexOf("."))
|
||||
);
|
||||
}
|
||||
return language;
|
||||
}
|
||||
|
||||
async function list(opts: GlobalOptions & { showArchived?: boolean }) {
|
||||
|
||||
@@ -133,6 +133,7 @@ function ZipFSElement(zip: JSZip, useYaml: boolean): DynFSElement {
|
||||
else if (language == "deno") ext = "ts";
|
||||
else if (language == "go") ext = "go";
|
||||
else if (language == "bash") ext = "sh";
|
||||
else if (language == "powershell") ext = "ps1";
|
||||
else if (language == "postgresql") ext = "pg.sql";
|
||||
else if (language == "mysql") ext = "my.sql";
|
||||
else if (language == "bigquery") ext = "bq.sql";
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ services:
|
||||
- KEEP_JOB_DIR=false
|
||||
- METRICS_ADDR=false
|
||||
# To handle all tags, remove the env variable altogether. If you do so, you can remove the windmill_worker_native containers.
|
||||
- WORKER_TAGS=deno,python3,go,bash,dependency,flow,hub,other,bun
|
||||
- WORKER_TAGS=deno,python3,go,bash,powershell,dependency,flow,hub,other,bun
|
||||
# LICENSE_KEY is only needed for the enterprise edition
|
||||
- LICENSE_KEY=${WM_LICENSE_KEY}
|
||||
depends_on:
|
||||
|
||||
Generated
+7
-7
@@ -43,7 +43,7 @@
|
||||
"svelte-timezone-picker": "^2.0.3",
|
||||
"tailwind-merge": "^1.13.2",
|
||||
"vscode-ws-jsonrpc": "3.0.0",
|
||||
"windmill-parser-wasm": "^1.141.0",
|
||||
"windmill-parser-wasm": "^1.143.0",
|
||||
"y-monaco": "^0.1.4",
|
||||
"y-websocket": "^1.5.0",
|
||||
"yjs": "^13.6.7"
|
||||
@@ -9811,9 +9811,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/windmill-parser-wasm": {
|
||||
"version": "1.141.0",
|
||||
"resolved": "https://registry.npmjs.org/windmill-parser-wasm/-/windmill-parser-wasm-1.141.0.tgz",
|
||||
"integrity": "sha512-2U4wAyKOMa7YTcWGUSCCqhNEfI+dVF9JvlXzPneOUO9nD7zm5uXRB+xaJLHKtYB5gmzLz1cQElp/FpbJaLLZsw=="
|
||||
"version": "1.143.0",
|
||||
"resolved": "https://registry.npmjs.org/windmill-parser-wasm/-/windmill-parser-wasm-1.143.0.tgz",
|
||||
"integrity": "sha512-sxkolDrUX/ywrE3tZpA3f9B4BONpW7PaHq+5qJBreCBHVkGnAx8iyXgyEvZhIpcTmuNhCy/osumoK/CjxGWWDw=="
|
||||
},
|
||||
"node_modules/wordwrap": {
|
||||
"version": "1.0.0",
|
||||
@@ -16782,9 +16782,9 @@
|
||||
}
|
||||
},
|
||||
"windmill-parser-wasm": {
|
||||
"version": "1.141.0",
|
||||
"resolved": "https://registry.npmjs.org/windmill-parser-wasm/-/windmill-parser-wasm-1.141.0.tgz",
|
||||
"integrity": "sha512-2U4wAyKOMa7YTcWGUSCCqhNEfI+dVF9JvlXzPneOUO9nD7zm5uXRB+xaJLHKtYB5gmzLz1cQElp/FpbJaLLZsw=="
|
||||
"version": "1.143.0",
|
||||
"resolved": "https://registry.npmjs.org/windmill-parser-wasm/-/windmill-parser-wasm-1.143.0.tgz",
|
||||
"integrity": "sha512-sxkolDrUX/ywrE3tZpA3f9B4BONpW7PaHq+5qJBreCBHVkGnAx8iyXgyEvZhIpcTmuNhCy/osumoK/CjxGWWDw=="
|
||||
},
|
||||
"wordwrap": {
|
||||
"version": "1.0.0",
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
"svelte-timezone-picker": "^2.0.3",
|
||||
"tailwind-merge": "^1.13.2",
|
||||
"vscode-ws-jsonrpc": "3.0.0",
|
||||
"windmill-parser-wasm": "^1.141.0",
|
||||
"windmill-parser-wasm": "^1.143.0",
|
||||
"y-monaco": "^0.1.4",
|
||||
"y-websocket": "^1.5.0",
|
||||
"yjs": "^13.6.7"
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
export function setDiff(
|
||||
original: string,
|
||||
modified: string,
|
||||
lang: 'typescript' | 'python' | 'go' | 'shell' | 'sql' | 'graphql' | 'javascript'
|
||||
lang: 'typescript' | 'python' | 'go' | 'shell' | 'sql' | 'graphql' | 'javascript' | 'powershell'
|
||||
): void {
|
||||
diffEditor?.setModel({
|
||||
original: meditor.createModel(original, lang),
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
import 'monaco-editor/esm/vs/basic-languages/typescript/typescript.contribution'
|
||||
import 'monaco-editor/esm/vs/basic-languages/sql/sql.contribution'
|
||||
import 'monaco-editor/esm/vs/basic-languages/graphql/graphql.contribution'
|
||||
import 'monaco-editor/esm/vs/basic-languages/powershell/powershell.contribution'
|
||||
import 'monaco-editor/esm/vs/language/typescript/monaco.contribution'
|
||||
import { MonacoLanguageClient, initServices } from 'monaco-languageclient'
|
||||
import { toSocket, WebSocketMessageReader, WebSocketMessageWriter } from 'vscode-ws-jsonrpc'
|
||||
@@ -48,7 +49,7 @@
|
||||
let divEl: HTMLDivElement | null = null
|
||||
let editor: meditor.IStandaloneCodeEditor
|
||||
|
||||
export let lang: 'typescript' | 'python' | 'go' | 'shell' | 'sql' | 'graphql'
|
||||
export let lang: 'typescript' | 'python' | 'go' | 'shell' | 'sql' | 'graphql' | 'powershell'
|
||||
export let deno: boolean
|
||||
export let code: string = ''
|
||||
export let cmdEnterAction: (() => void) | undefined = undefined
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
langs.push(['BigQuery', Script.language.BIGQUERY])
|
||||
langs.push(['Snowflake', Script.language.SNOWFLAKE])
|
||||
langs.push(['GraphQL', Script.language.GRAPHQL])
|
||||
langs.push(['PowerShell', Script.language.POWERSHELL])
|
||||
if (SCRIPT_SHOW_GO) {
|
||||
langs.push(['Go', Script.language.GO])
|
||||
}
|
||||
@@ -365,22 +366,6 @@
|
||||
>
|
||||
<LanguageIcon lang="docker" /><span class="ml-2 py-2">Docker</span>
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="border"
|
||||
color={template == 'powershell' ? 'blue' : 'light'}
|
||||
btnClasses={template == 'powershell'
|
||||
? '!border-2 !bg-blue-50/75 dark:!bg-frost-900/75'
|
||||
: 'm-[1px]'}
|
||||
disabled={lockedLanguage}
|
||||
on:click={() => {
|
||||
template = 'powershell'
|
||||
initContent(Script.language.BASH, script.kind, template)
|
||||
script.language = Script.language.BASH
|
||||
}}
|
||||
>
|
||||
<LanguageIcon lang="powershell" /><span class="ml-2 py-2">Powershell</span>
|
||||
</Button>
|
||||
<Button
|
||||
size="xs"
|
||||
variant="border"
|
||||
|
||||
@@ -98,6 +98,7 @@
|
||||
['python3', 'Python'],
|
||||
['go', 'Go'],
|
||||
['bash', 'Bash'],
|
||||
['powershell', 'PowerShell'],
|
||||
['nativets', 'REST'],
|
||||
['postgresql', 'PostgreSQL'],
|
||||
['mysql', 'MySQL'],
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
[Script.language.DENO]: 'TypeScript',
|
||||
[Script.language.GO]: 'Go',
|
||||
[Script.language.BASH]: 'Bash',
|
||||
[Script.language.POWERSHELL]: 'PowerShell',
|
||||
[Script.language.NATIVETS]: 'HTTP',
|
||||
[Script.language.GRAPHQL]: 'GraphQL',
|
||||
[Script.language.POSTGRESQL]: 'Postgresql',
|
||||
|
||||
@@ -224,10 +224,14 @@
|
||||
/>
|
||||
|
||||
<FlowScriptPicker
|
||||
label={`Powershell`}
|
||||
lang="powershell"
|
||||
label="PowerShell"
|
||||
lang={Script.language.POWERSHELL}
|
||||
on:click={() => {
|
||||
dispatch('new', { language: RawScript.language.BASH, kind, subkind: 'powershell' })
|
||||
dispatch('new', {
|
||||
language: RawScript.language.POWERSHELL,
|
||||
kind,
|
||||
subkind: 'flow'
|
||||
})
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
@@ -59,6 +59,8 @@ export function langToExt(lang: string): string {
|
||||
return 'go'
|
||||
case 'bash':
|
||||
return 'sh'
|
||||
case 'powershell':
|
||||
return 'ps1'
|
||||
case 'deno':
|
||||
return 'ts'
|
||||
case 'nativets':
|
||||
|
||||
@@ -12,7 +12,8 @@ import init, {
|
||||
parse_mysql,
|
||||
parse_bigquery,
|
||||
parse_snowflake,
|
||||
parse_graphql
|
||||
parse_graphql,
|
||||
parse_powershell
|
||||
} from 'windmill-parser-wasm'
|
||||
import wasmUrl from 'windmill-parser-wasm/windmill_parser_wasm_bg.wasm?url'
|
||||
import { workspaceStore } from './stores.js'
|
||||
@@ -71,6 +72,8 @@ export async function inferArgs(
|
||||
inferedSchema = JSON.parse(parse_go(code))
|
||||
} else if (language == 'bash') {
|
||||
inferedSchema = JSON.parse(parse_bash(code))
|
||||
} else if (language == 'powershell') {
|
||||
inferedSchema = JSON.parse(parse_powershell(code))
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -260,17 +260,10 @@ docker pull $IMAGE
|
||||
docker run --rm $IMAGE $COMMAND
|
||||
`
|
||||
|
||||
export const POWERSHELL_INIT_CODE = `# shellcheck shell=bash
|
||||
name="\${1:-Bill}"
|
||||
export const POWERSHELL_INIT_CODE = `param($Msg, $Dflt = "default value", [int]$Nb = 3)
|
||||
|
||||
cat > script.ps1 << EOF
|
||||
Write-Host -Object 'Hello'
|
||||
Write-Host -Object 'From'
|
||||
Write-Host -Object 'PowerShell, '
|
||||
Write-Host -Object '$name!'
|
||||
EOF
|
||||
|
||||
pwsh -File script.ps1`
|
||||
# the last line of the stdout is the return value
|
||||
Write-Output "Hello $Msg"`
|
||||
|
||||
const ALL_INITIAL_CODE = [
|
||||
PYTHON_INIT_CODE,
|
||||
@@ -285,7 +278,9 @@ const ALL_INITIAL_CODE = [
|
||||
DENO_INIT_CODE_CLEAR,
|
||||
PYTHON_INIT_CODE_CLEAR,
|
||||
DENO_INIT_CODE_APPROVAL,
|
||||
DENO_FAILURE_MODULE_CODE
|
||||
DENO_FAILURE_MODULE_CODE,
|
||||
BASH_INIT_CODE,
|
||||
POWERSHELL_INIT_CODE
|
||||
]
|
||||
|
||||
export function isInitialCode(content: string): boolean {
|
||||
@@ -340,11 +335,11 @@ export function initialCode(
|
||||
} else if (language == 'bash') {
|
||||
if (subkind === 'docker') {
|
||||
return DOCKER_INIT_CODE
|
||||
} else if (subkind === 'powershell') {
|
||||
return POWERSHELL_INIT_CODE
|
||||
} else {
|
||||
return BASH_INIT_CODE
|
||||
}
|
||||
} else if (language == 'powershell') {
|
||||
return POWERSHELL_INIT_CODE
|
||||
} else if (language == 'nativets') {
|
||||
return NATIVETS_INIT_CODE
|
||||
} else if (language == 'postgresql') {
|
||||
|
||||
@@ -24,6 +24,8 @@ export function scriptLangToEditorLang(lang: Script.language) {
|
||||
return 'python'
|
||||
} else if (lang == 'bash') {
|
||||
return 'shell'
|
||||
} else if (lang == 'powershell') {
|
||||
return 'powershell'
|
||||
} else if (lang == 'graphql') {
|
||||
return 'graphql'
|
||||
} else {
|
||||
|
||||
@@ -291,7 +291,7 @@
|
||||
<Badge color="blue">{job.job_kind}</Badge>
|
||||
</div>
|
||||
{/if}
|
||||
{#if job.tag && !['deno', 'python3', 'flow', 'other', 'go', 'postgresql', 'mysql', 'bigquery', 'snowflake', 'graphql', 'nativets', 'bash', 'other', 'dependency'].includes(job.tag)}
|
||||
{#if job.tag && !['deno', 'python3', 'flow', 'other', 'go', 'postgresql', 'mysql', 'bigquery', 'snowflake', 'graphql', 'nativets', 'bash', 'powershell', 'other', 'dependency'].includes(job.tag)}
|
||||
<div>
|
||||
<Badge color="indigo">Worker group: {job.tag}</Badge>
|
||||
</div>
|
||||
|
||||
@@ -192,6 +192,7 @@ components:
|
||||
- python3
|
||||
- go
|
||||
- bash
|
||||
- powershell
|
||||
- postgresql
|
||||
- mysql
|
||||
- bigquery
|
||||
|
||||
Reference in New Issue
Block a user