Files
windmill/frontend/src/lib/scripts.ts
pyranota 4341c14f8e feat: add ruby support (#5939)
* implement single line pin

* make panic-safe

* use pin even if multiple modules imported withing single statement

* add repins and make imports respect pins

* keep all pins

* Allow multiple pins

* add comments + handle stuff more safely

* fix fully qualified imports

* remove ignore

* sort nested

* apply unique to output requirements list

* fix typo

* remove mut

* update sqlx

* sort imports

* sort imports

* fix formatter and format

* feat: add ruby support

* fix

* update sqlx

* add ruby to flake.nix

Signed-off-by: pyranota <pyra@duck.com>

* upgrade par_install_language_dependencies helper

rename fields + allow passing custom payload

Signed-off-by: pyranota <pyra@duck.com>

* change migrations

Signed-off-by: pyranota <pyra@duck.com>

* make full pipeline work!

Signed-off-by: pyranota <pyra@duck.com>

* do a bit fixing

* stage

Signed-off-by: pyranota <pyra@duck.com>

* add ruby in dockerfiles

Signed-off-by: pyranota <pyra@duck.com>

* implement auto-require + 'windmill/inline'

Signed-off-by: pyranota <pyra@duck.com>

* create 'windmill/inline' only if does not exist

Signed-off-by: pyranota <pyra@duck.com>

* add nsjail

Signed-off-by: pyranota <pyra@duck.com>

* update global settings

Signed-off-by: pyranota <pyra@duck.com>

* add ruby icon

* generate lockfile on deploy (but broken)

Signed-off-by: pyranota <pyra@duck.com>

* fix(frontend): display deployed script lockfile and other info

Signed-off-by: pyranota <pyra@duck.com>

* feat: add mini-wmill client

Methods:
- get_resource
- get_variable

Additionally add shortcuts on frontend

Signed-off-by: pyranota <pyra@duck.com>

* add nit warning

Signed-off-by: pyranota <pyra@duck.com>

* support private repos credentials

Signed-off-by: pyranota <pyra@duck.com>

* fix compilation error

Signed-off-by: pyranota <pyra@duck.com>

* found rustc bug + refactor universal installer

Signed-off-by: pyranota <pyra@duck.com>

* more refactor + fixes

Signed-off-by: pyranota <pyra@duck.com>

* bug fixing + polishing

Signed-off-by: pyranota <pyra@duck.com>

* cleanup

Signed-off-by: pyranota <pyra@duck.com>

* change 'windmill/inline'

Signed-off-by: pyranota <pyra@duck.com>

* delegate env_clear to universal installer

Signed-off-by: pyranota <pyra@duck.com>

* update init script

Signed-off-by: pyranota <pyra@duck.com>

* add cli support

Signed-off-by: pyranota <pyra@duck.com>

* unhardcode frontend

Signed-off-by: pyranota <pyra@duck.com>

* fix cli

Signed-off-by: pyranota <pyra@duck.com>

* fix init script

Signed-off-by: pyranota <pyra@duck.com>

* make it work on ms windows

Signed-off-by: pyranota <pyra@duck.com>

* do not clean env in the end

Signed-off-by: pyranota <pyra@duck.com>

* fix windows (again)

Signed-off-by: pyranota <pyra@duck.com>

* include PROXY_ENVS (untested)

Signed-off-by: pyranota <pyra@duck.com>

* feat: self-signed certs + proxy support (tested)

Signed-off-by: pyranota <pyra@duck.com>

* flake: pin ruby to 3.4

* merge follow-ups

Signed-off-by: pyranota <pyra@duck.com>

* remove obsolete libc crate

Signed-off-by: pyranota <pyra@duck.com>

* cleanup parser

Signed-off-by: pyranota <pyra@duck.com>

* fix java ci

Signed-off-by: pyranota <pyra@duck.com>

* cleanup

Signed-off-by: pyranota <pyra@duck.com>

* fix nits

Signed-off-by: pyranota <pyra@duck.com>

* Update backend/windmill-worker/src/universal_pkg_installer.rs

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* Update backend/windmill-worker/src/ruby_executor.rs

Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>

* add nsjail for lock stage

Signed-off-by: pyranota <pyra@duck.com>

* fix merge

Signed-off-by: pyranota <pyra@duck.com>

* Update common.rs

* regen windmill-api-client

Signed-off-by: pyranota <pyra@duck.com>

* fix tests

Signed-off-by: pyranota <pyra@duck.com>

* fix tests again

Signed-off-by: pyranota <pyra@duck.com>

* reference published ruby parser

Signed-off-by: pyranota <pyra@duck.com>

---------

Signed-off-by: pyranota <pyra@duck.com>
Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
2025-08-15 13:03:32 +00:00

222 lines
5.4 KiB
TypeScript

import { get } from 'svelte/store'
import { base } from '$lib/base'
import type { Schema, SupportedLanguage } from './common'
import { FlowService, type Script, ScriptService, ScheduleService } from './gen'
import { workspaceStore } from './stores'
export function scriptLangToEditorLang(
lang:
| Script['language']
| 'bunnative'
| 'javascript'
| 'frontend'
| 'jsx'
| 'tsx'
| 'text'
| 'json'
| undefined
) {
if (lang == 'deno') {
return 'typescript'
} else if (lang == 'bun' || lang == 'bunnative' || lang == 'frontend' || lang == 'tsx') {
return 'typescript'
} else if (lang == 'nativets') {
return 'typescript'
} else if (lang == 'text') {
return 'text'
} else if (lang == 'javascript' || lang == 'jsx') {
return 'javascript'
} else if (lang == 'postgresql') {
return 'sql'
} else if (lang == 'mysql') {
return 'sql'
} else if (lang == 'bigquery') {
return 'sql'
} else if (lang == 'oracledb') {
return 'sql'
} else if (lang == 'snowflake') {
return 'sql'
} else if (lang == 'mssql') {
return 'sql'
} else if (lang == 'duckdb') {
return 'sql'
} else if (lang == 'python3') {
return 'python'
} else if (lang == 'bash') {
return 'shell'
} else if (lang == 'powershell') {
return 'powershell'
} else if (lang == 'php') {
return 'php'
} else if (lang == 'rust') {
return 'rust'
} else if (lang == 'graphql') {
return 'graphql'
} else if (lang == 'ansible') {
return 'yaml'
} else if (lang == 'csharp') {
return 'csharp'
} else if (lang == 'nu') {
return 'nu'
} else if (lang == 'java') {
return 'java'
// for related places search: ADD_NEW_LANG
} else if (lang == undefined) {
return 'typescript'
} else {
return lang
}
}
export type ScriptSchedule = {
summary: string | undefined
args: Record<string, any>
cron: string
timezone: string
enabled: boolean
}
// Load the schedule of a flow given its path and the workspace
export async function loadScriptSchedule(
path: string,
workspace: string
): Promise<ScriptSchedule | undefined> {
const existsSchedule = await ScheduleService.existsSchedule({
workspace,
path
})
if (!existsSchedule) {
return undefined
}
const schedule = await ScheduleService.getSchedule({
workspace,
path
})
return {
summary: schedule.summary,
enabled: schedule.enabled,
cron: schedule.schedule,
timezone: schedule.timezone,
args: schedule.args ?? {}
}
}
export async function loadSchemaFlow(path: string): Promise<Schema> {
const flow = await FlowService.getFlowByPath({
workspace: get(workspaceStore)!,
path: path ?? ''
})
return flow.schema as any
}
export function scriptPathToHref(path: string, hubBaseUrl: string): string {
if (path.startsWith('hub/')) {
return hubBaseUrl + '/from_version/' + path.substring(4)
} else {
return `${base}/scripts/get/${path}?workspace=${get(workspaceStore)}`
}
}
const scriptLanguagesArray: [SupportedLanguage | 'docker' | 'bunnative', string][] = [
['bun', 'TypeScript (Bun)'],
['python3', 'Python'],
['deno', 'TypeScript (Deno)'],
['bash', 'Bash'],
['go', 'Go'],
['nativets', 'REST'],
['bunnative', 'REST'],
['postgresql', 'PostgreSQL'],
['mysql', 'MySQL'],
['bigquery', 'BigQuery'],
['oracledb', 'Oracle Database'],
['snowflake', 'Snowflake'],
['mssql', 'MS SQL Server'],
['graphql', 'GraphQL'],
['powershell', 'PowerShell'],
['php', 'PHP'],
['rust', 'Rust'],
['ansible', 'Ansible'],
['csharp', 'C#'],
['docker', 'Docker'],
['nu', 'Nu'],
['java', 'Java'],
['duckdb', 'DuckDB'],
['ruby', 'Ruby']
// for related places search: ADD_NEW_LANG
]
export function processLangs(selected: string | undefined, langs: string[]): string[] {
if (selected === 'nativets') {
return langs
} else {
let ls = langs.filter((lang) => lang !== 'nativets')
//those languages are newer and may not be in the saved list
let nl = ['bunnative', 'rust', 'ansible', 'csharp', 'nu', 'java', 'duckdb', 'ruby']
// for related places search: ADD_NEW_LANG
nl.forEach((lang) => {
if (!ls.includes(lang)) {
ls.push(lang)
}
})
return ls
}
}
export const defaultScriptLanguages = Object.fromEntries(scriptLanguagesArray)
export async function getScriptByPath(path: string): Promise<{
content: string
language: SupportedLanguage
schema: any
description: string
tag: string | undefined
concurrent_limit: number | undefined
concurrency_time_window_s: number | undefined
lock?: string
created_at?: string
hash?: string
}> {
if (path.startsWith('hub/')) {
const { content, language, schema, lockfile } = await ScriptService.getHubScriptByPath({ path })
return {
content,
language: language as SupportedLanguage,
schema,
description: '',
tag: undefined,
concurrent_limit: undefined,
concurrency_time_window_s: undefined,
lock: lockfile
}
} else {
const script = await ScriptService.getScriptByPath({
workspace: get(workspaceStore)!,
path: path ?? ''
})
return {
content: script.content,
language: script.language,
schema: script.schema,
description: script.description,
tag: script.tag,
concurrent_limit: script.concurrent_limit,
concurrency_time_window_s: script.concurrency_time_window_s,
lock: script.lock,
hash: script.hash,
created_at: script.created_at
}
}
}
export async function getLatestHashForScript(path: string): Promise<string> {
const script = await ScriptService.getScriptByPath({
workspace: get(workspaceStore)!,
path: path ?? ''
})
return script.hash
}