Compare commits

..

2 Commits

Author SHA1 Message Date
wendrul
ba775edef2 Merge remote-tracking branch 'origin/main' into folder-deploy
# Conflicts:
#	frontend/src/lib/utils_workspace_deploy.ts
2026-04-02 15:39:36 +02:00
wendrul
91f0a564b9 fix: deployment UIs for folders 2026-04-02 15:33:12 +02:00
281 changed files with 1529 additions and 9207 deletions

1
.gitignore vendored
View File

@@ -29,4 +29,3 @@ frontend/.svelte-kit
backend/chrome_profiler.json
.fast-check/
__pycache__/
.playwright-mcp/

View File

@@ -1,32 +1,5 @@
# Changelog
## [1.673.0](https://github.com/windmill-labs/windmill/compare/v1.672.0...v1.673.0) (2026-04-02)
### Features
* add endpoint to restart workers in a worker group ([#8659](https://github.com/windmill-labs/windmill/issues/8659)) ([f0437eb](https://github.com/windmill-labs/windmill/commit/f0437eba1925a9aa4c430008027d637a0c89ee39))
* add Entra ID (Azure Workload Identity) database auth ([#8526](https://github.com/windmill-labs/windmill/issues/8526)) ([6a5cfbc](https://github.com/windmill-labs/windmill/commit/6a5cfbc159a0ad7925fd7ce5eefc8eaa21bbb70b))
* add LIMIT_WINDOWS_TO_1CU env var for Windows worker memory limits ([#8681](https://github.com/windmill-labs/windmill/issues/8681)) ([d2d6810](https://github.com/windmill-labs/windmill/commit/d2d6810db954114f3333853bd3476cb8fc735f92))
* restore bun for dedicated workers, fix dispatch & serialization, cross-workspace deps ([#8645](https://github.com/windmill-labs/windmill/issues/8645)) ([619ebb6](https://github.com/windmill-labs/windmill/commit/619ebb65ce8dce8264add31c3147919802a8286a))
### Bug Fixes
* add HMAC signature verification to Slack interactive callback endpoint ([#8611](https://github.com/windmill-labs/windmill/issues/8611)) ([55e8a5c](https://github.com/windmill-labs/windmill/commit/55e8a5cff1f185b1dbd332d37b877972efa1ed7d))
* correct raw app flow inputs ([#8667](https://github.com/windmill-labs/windmill/issues/8667)) ([28c0730](https://github.com/windmill-labs/windmill/commit/28c073056c65d4ed1600e39679497e5af964347f))
* pass selected language to AI agent when generating flow scripts ([#8680](https://github.com/windmill-labs/windmill/issues/8680)) ([381011a](https://github.com/windmill-labs/windmill/commit/381011a4a8e48454e9c146c64db502293e646b99))
* poll for preview results to avoid undici headers timeout ([#8682](https://github.com/windmill-labs/windmill/issues/8682)) ([ff5fa9f](https://github.com/windmill-labs/windmill/commit/ff5fa9f64fe4aaf33e06b20f02373894b5df0f95))
* pre-fix trigger edited_by for superadmins not in workspace ([#8669](https://github.com/windmill-labs/windmill/issues/8669)) ([350ffdc](https://github.com/windmill-labs/windmill/commit/350ffdce297ba5b84f9dd247eede6da0c6b0956c))
* resolve race condition where flow sync push reverts to stale version ([#8673](https://github.com/windmill-labs/windmill/issues/8673)) ([d569e9e](https://github.com/windmill-labs/windmill/commit/d569e9e29c588243a90b1cd25f866efb0d178640))
* respect disabled fields in JSON input mode ([#8663](https://github.com/windmill-labs/windmill/issues/8663)) ([7fd0bf9](https://github.com/windmill-labs/windmill/commit/7fd0bf974d2ba2644bb01dd5e9ddc84749e166f5))
* Run typed pg queries in a single protocol conversation ([#8679](https://github.com/windmill-labs/windmill/issues/8679)) ([8581a33](https://github.com/windmill-labs/windmill/commit/8581a3300d056040b7e3ab77d629c74f034c9c97))
* sanitize MCP tool schemas for JSON Schema draft 2020-12 compliance ([#8666](https://github.com/windmill-labs/windmill/issues/8666)) ([8c3c97f](https://github.com/windmill-labs/windmill/commit/8c3c97f7a670d47019cc666219f8187f48499672))
* skip generate-metadata confirmation prompt in non-interactive CI ([#8678](https://github.com/windmill-labs/windmill/issues/8678)) ([39af1b7](https://github.com/windmill-labs/windmill/commit/39af1b75afc8458f85dec4fe51dfaed3d0cb000d))
* strip f/ prefix from folder paths when deploying from workspace forks ([#8662](https://github.com/windmill-labs/windmill/issues/8662)) ([7ab0ea5](https://github.com/windmill-labs/windmill/commit/7ab0ea581d349fbfdb56d22cf9903a90efa045bb))
* support branch-specific folder.meta.yaml in missing-meta check ([#8661](https://github.com/windmill-labs/windmill/issues/8661)) ([c87a6a0](https://github.com/windmill-labs/windmill/commit/c87a6a0f2c1346bf5e21f128d32d89bdca039243))
* validate rd redirect on login with same rules as logout ([#8655](https://github.com/windmill-labs/windmill/issues/8655)) ([bcce627](https://github.com/windmill-labs/windmill/commit/bcce62738791a4e9b9f4dbc64731eef163230172))
## [1.672.0](https://github.com/windmill-labs/windmill/compare/v1.671.0...v1.672.0) (2026-04-01)

View File

@@ -26,7 +26,6 @@ Open-source platform for internal tools, workflows, API integrations, background
- **DB**: `psql postgres://postgres:changeme@localhost:5432/windmill`
- **Login**: `admin@windmill.dev` / `changeme`
- **Instance settings**: navigate to `/#superadmin-settings`
- **Migrations**: use `cargo sqlx migrate add -r <name>` from `backend/` to create new migrations (never generate timestamps manually)
## Banned Patterns

View File

@@ -34,8 +34,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "WITH inserted_job AS (\n INSERT INTO v2_job (\n id, -- 1\n workspace_id, -- 2\n raw_code, -- 3\n raw_lock, -- 4\n raw_flow, -- 5\n tag, -- 6\n parent_job, -- 7\n created_by, -- 8\n permissioned_as, -- 9\n runnable_id, -- 10\n runnable_path, -- 11\n args, -- 12\n kind, -- 13\n trigger, -- 14\n script_lang, -- 15\n same_worker, -- 16\n pre_run_error, -- 17 \n permissioned_as_email, -- 18\n visible_to_owner, -- 19\n flow_innermost_root_job, -- 20\n root_job, -- 38\n concurrent_limit, -- 21\n concurrency_time_window_s, -- 22\n timeout, -- 23\n flow_step_id, -- 24\n cache_ttl, -- 25\n priority, -- 26\n trigger_kind, -- 39\n script_entrypoint_override, -- 12\n preprocessed, -- 27,\n labels -- 44\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18,\n $19, $20, $38, $21, $22, $23, $24, $25, $26, $39::job_trigger_kind,\n ($12::JSONB)->>'_ENTRYPOINT_OVERRIDE', $27, $44)\n ),\n inserted_runtime AS (\n INSERT INTO v2_job_runtime (id, ping) VALUES ($1, null)\n ),\n inserted_job_perms AS (\n INSERT INTO job_perms (job_id, email, username, is_admin, is_operator, folders, groups, workspace_id, end_user_email) \n values ($1, $32, $33, $34, $35, $36, $37, $2, $41) \n ON CONFLICT (job_id) DO UPDATE SET email = EXCLUDED.email, username = EXCLUDED.username, is_admin = EXCLUDED.is_admin, is_operator = EXCLUDED.is_operator, folders = EXCLUDED.folders, groups = EXCLUDED.groups, workspace_id = EXCLUDED.workspace_id, end_user_email = EXCLUDED.end_user_email\n )\n INSERT INTO v2_job_queue\n (workspace_id, id, running, scheduled_for, started_at, tag, priority, cache_ignore_s3_path, runnable_settings_handle)\n VALUES ($2, $1, $28, COALESCE($29, now()), CASE WHEN $27 OR $40 THEN now() END, $30, $31, $42, $43)",
"query": "WITH inserted_job AS (\n INSERT INTO v2_job (\n id, -- 1\n workspace_id, -- 2\n raw_code, -- 3\n raw_lock, -- 4\n raw_flow, -- 5\n tag, -- 6\n parent_job, -- 7\n created_by, -- 8\n permissioned_as, -- 9\n runnable_id, -- 10\n runnable_path, -- 11\n args, -- 12\n kind, -- 13\n trigger, -- 14\n script_lang, -- 15\n same_worker, -- 16\n pre_run_error, -- 17 \n permissioned_as_email, -- 18\n visible_to_owner, -- 19\n flow_innermost_root_job, -- 20\n root_job, -- 38\n concurrent_limit, -- 21\n concurrency_time_window_s, -- 22\n timeout, -- 23\n flow_step_id, -- 24\n cache_ttl, -- 25\n priority, -- 26\n trigger_kind, -- 39\n script_entrypoint_override, -- 12\n preprocessed -- 27,\n ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18,\n $19, $20, $38, $21, $22, $23, $24, $25, $26, $39::job_trigger_kind,\n ($12::JSONB)->>'_ENTRYPOINT_OVERRIDE', $27)\n ),\n inserted_runtime AS (\n INSERT INTO v2_job_runtime (id, ping) VALUES ($1, null)\n ),\n inserted_job_perms AS (\n INSERT INTO job_perms (job_id, email, username, is_admin, is_operator, folders, groups, workspace_id, end_user_email) \n values ($1, $32, $33, $34, $35, $36, $37, $2, $41) \n ON CONFLICT (job_id) DO UPDATE SET email = EXCLUDED.email, username = EXCLUDED.username, is_admin = EXCLUDED.is_admin, is_operator = EXCLUDED.is_operator, folders = EXCLUDED.folders, groups = EXCLUDED.groups, workspace_id = EXCLUDED.workspace_id, end_user_email = EXCLUDED.end_user_email\n )\n INSERT INTO v2_job_queue\n (workspace_id, id, running, scheduled_for, started_at, tag, priority, cache_ignore_s3_path, runnable_settings_handle)\n VALUES ($2, $1, $28, COALESCE($29, now()), CASE WHEN $27 OR $40 THEN now() END, $30, $31, $42, $43)",
"describe": {
"columns": [],
"parameters": {
@@ -76,8 +76,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}
@@ -132,11 +131,10 @@
"Bool",
"Varchar",
"Bool",
"Int8",
"TextArray"
"Int8"
]
},
"nullable": []
},
"hash": "5425e2c5e29fc5145dde5ea53d5307ca90d8dd76da2ca560b310b12820be2576"
"hash": "14276a040cb4db88d71fccdc3579e8c0bb132b70668301b535872d1632753e30"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n NULLIF(script_lang, 'other')::script_lang as \"language: _\",\n SUM(job_count)::BIGINT as \"count!\",\n SUM(total_duration_ms)::BIGINT as \"total_duration!\"\n FROM worker_group_job_stats\n WHERE hour >= $1 AND hour < $2\n GROUP BY script_lang\n ",
"query": "\n SELECT\n script_lang as \"language: _\",\n COUNT(*) as \"count!\",\n SUM(duration_ms)::BIGINT as \"total_duration!\"\n FROM\n v2_job_completed\n JOIN\n v2_job\n ON\n v2_job.id = v2_job_completed.id\n WHERE\n created_at >= CURRENT_DATE - INTERVAL '1 day'\n AND created_at < CURRENT_DATE\n GROUP BY\n script_lang\n ",
"describe": {
"columns": [
{
@@ -33,8 +33,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}
@@ -52,16 +51,13 @@
}
],
"parameters": {
"Left": [
"Int8",
"Int8"
]
"Left": []
},
"nullable": [
null,
true,
null,
null
]
},
"hash": "6348061d79b0b6b25bda7425f7a37344e04107f060f949cc197b4df9bca18fb8"
"hash": "19478c2a3c05b2ed17b110f8ff58d48ce3ede5fdd7f8d64840f8c62cf89f99e7"
}

View File

@@ -43,8 +43,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n flow_version.id AS version,\n flow_version.value->>'early_return' as early_return,\n flow_version.value->>'preprocessor_module' IS NOT NULL as has_preprocessor,\n (flow_version.value->>'chat_input_enabled')::boolean as chat_input_enabled,\n flow.tag,\n flow.dedicated_worker,\n flow.on_behalf_of_email,\n flow.edited_by,\n flow.labels\n FROM\n flow_version\n INNER JOIN flow\n ON flow.path = flow_version.path AND\n flow.workspace_id = flow_version.workspace_id\n WHERE\n flow_version.workspace_id = $1 AND\n flow_version.path = $2 AND\n flow_version.id = $3\n ",
"query": "\n SELECT\n flow_version.id AS version,\n flow_version.value->>'early_return' as early_return,\n flow_version.value->>'preprocessor_module' IS NOT NULL as has_preprocessor,\n (flow_version.value->>'chat_input_enabled')::boolean as chat_input_enabled,\n flow.tag,\n flow.dedicated_worker,\n flow.on_behalf_of_email,\n flow.edited_by\n FROM\n flow_version\n INNER JOIN flow\n ON flow.path = flow_version.path AND\n flow.workspace_id = flow_version.workspace_id\n WHERE\n flow_version.workspace_id = $1 AND\n flow_version.path = $2 AND\n flow_version.id = $3\n ",
"describe": {
"columns": [
{
@@ -42,11 +42,6 @@
"ordinal": 7,
"name": "edited_by",
"type_info": "Varchar"
},
{
"ordinal": 8,
"name": "labels",
"type_info": "TextArray"
}
],
"parameters": {
@@ -64,9 +59,8 @@
true,
true,
true,
false,
true
false
]
},
"hash": "6d992a933bb878733b7afd7a4295b9ad6f5276b60ce20e0378d6148976e02777"
"hash": "209dc4c1b91eeab1c12ffcd9f9e16f315c689ca772c736b333dcdf07c8086087"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO variable\n (workspace_id, path, value, is_secret, description, account, is_oauth, expires_at, labels)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
"query": "INSERT INTO variable\n (workspace_id, path, value, is_secret, description, account, is_oauth, expires_at)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8)",
"describe": {
"columns": [],
"parameters": {
@@ -12,11 +12,10 @@
"Varchar",
"Int4",
"Bool",
"Timestamptz",
"TextArray"
"Timestamptz"
]
},
"nullable": []
},
"hash": "48efd8f89df9c1dd8f8a4eb2b2640fcb380f2470c8488371b207a42cb7d4cd26"
"hash": "2be66f23536223549db9b50025932b6b1bad90b8fa47d97acb7d75aa3c37ef86"
}

View File

@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE flow SET versions = array_append(versions, $1) WHERE path = $2 AND workspace_id = $3 AND (versions[array_upper(versions, 1)] IS DISTINCT FROM $1)",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int8",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "32f26d69b15a74fc96dd585f9eb3c998447ca8b97894bb1a2b238f984c1dc588"
}

View File

@@ -0,0 +1,19 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO resource\n (workspace_id, path, value, description, resource_type, created_by, edited_at)\n VALUES ($1, $2, $3, $4, $5, $6, now()) ON CONFLICT (workspace_id, path)\n DO UPDATE SET value = EXCLUDED.value, description = EXCLUDED.description, resource_type = EXCLUDED.resource_type, edited_at = now()",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Varchar",
"Jsonb",
"Text",
"Varchar",
"Varchar"
]
},
"nullable": []
},
"hash": "39426bd3018b390ea2073419884cf6cb506c75e84c65438c9026831eb10d340b"
}

View File

@@ -45,36 +45,31 @@
},
{
"ordinal": 8,
"name": "labels",
"type_info": "TextArray"
},
{
"ordinal": 9,
"name": "is_expired",
"type_info": "Bool"
},
{
"ordinal": 10,
"ordinal": 9,
"name": "is_refreshed",
"type_info": "Bool"
},
{
"ordinal": 11,
"ordinal": 10,
"name": "refresh_error",
"type_info": "Text"
},
{
"ordinal": 12,
"ordinal": 11,
"name": "is_linked",
"type_info": "Bool"
},
{
"ordinal": 13,
"ordinal": 12,
"name": "is_oauth?",
"type_info": "Bool"
},
{
"ordinal": 14,
"ordinal": 13,
"name": "account",
"type_info": "Int4"
}
@@ -94,7 +89,6 @@
false,
true,
true,
true,
null,
null,
true,

View File

@@ -42,11 +42,6 @@
"ordinal": 7,
"name": "created_by",
"type_info": "Varchar"
},
{
"ordinal": 8,
"name": "labels",
"type_info": "TextArray"
}
],
"parameters": {
@@ -62,7 +57,6 @@
false,
false,
true,
true,
true
]
},

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n NULLIF(script_lang, 'other')::script_lang as \"language: _\",\n SUM(job_count)::BIGINT as \"count!\",\n SUM(total_duration_ms)::BIGINT as \"total_duration!\"\n FROM worker_group_job_stats\n WHERE hour >= $1\n GROUP BY script_lang\n ",
"query": "\n SELECT\n script_lang as \"language: _\",\n COUNT(*) as \"count!\",\n SUM(duration_ms)::BIGINT as \"total_duration!\"\n FROM\n v2_job_completed\n JOIN\n v2_job\n ON\n v2_job.id = v2_job_completed.id\n WHERE\n created_at > NOW() - INTERVAL '48 hours'\n GROUP BY\n script_lang\n ",
"describe": {
"columns": [
{
@@ -33,8 +33,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}
@@ -52,15 +51,13 @@
}
],
"parameters": {
"Left": [
"Int8"
]
"Left": []
},
"nullable": [
null,
true,
null,
null
]
},
"hash": "5c0d0c7111b70b119b3182c9195361388ead36dc6ab03c6a7c17fb97d2b60a67"
"hash": "464895f217536bf713ec381b6c3b7c0417161bf69e596e2e34fc8d9384824776"
}

View File

@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE variable SET labels = $1 WHERE path = $2 AND workspace_id = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"TextArray",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "4c333861e736b8138162f0ff3bf2844c71b95c75bd8f173eac51336ab176ccc0"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO script (workspace_id, hash, path, parent_hashes, summary, description, content, created_by, schema, is_template, extra_perms, lock, language, kind, tag, draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only, auto_kind, codebase, has_preprocessor, on_behalf_of_email, schema_validation, assets, debounce_key, debounce_delay_s, cache_ignore_s3_path, runnable_settings_handle, modules, labels) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::text::json, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34, $35, $36, $37, $38, $39, $40)",
"query": "INSERT INTO script (workspace_id, hash, path, parent_hashes, summary, description, content, created_by, schema, is_template, extra_perms, lock, language, kind, tag, draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only, auto_kind, codebase, has_preprocessor, on_behalf_of_email, schema_validation, assets, debounce_key, debounce_delay_s, cache_ignore_s3_path, runnable_settings_handle, modules) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::text::json, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32, $33, $34, $35, $36, $37, $38, $39)",
"describe": {
"columns": [],
"parameters": {
@@ -44,8 +44,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}
@@ -89,11 +88,10 @@
"Int4",
"Bool",
"Int8",
"Jsonb",
"TextArray"
"Jsonb"
]
},
"nullable": []
},
"hash": "790d79ec7abe6ebe1092afd9de4c5fc383272d2057ac5b47a7425f095f4e8788"
"hash": "4d983f1e3e63a1a70edf5d867d9f23f2069a7a4ba1dcc1331ecccdf1c6a95cb8"
}

View File

@@ -70,8 +70,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO script\n (workspace_id, hash, path, parent_hashes, summary, description, content, created_by, schema, is_template, extra_perms, lock, language, kind, tag, draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, cache_ignore_s3_path, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only, auto_kind, codebase, has_preprocessor, on_behalf_of_email, schema_validation, assets, debounce_key, debounce_delay_s, runnable_settings_handle, modules)\n\n SELECT workspace_id, $1, path, array_prepend($2::bigint, COALESCE(parent_hashes, '{}'::bigint[])), summary, description, content, created_by, schema, is_template, extra_perms, NULL, language, kind, tag, draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, cache_ignore_s3_path, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only, auto_kind, codebase, has_preprocessor, on_behalf_of_email, schema_validation, assets, debounce_key, debounce_delay_s, runnable_settings_handle, modules\n\n FROM script WHERE hash = $2 AND workspace_id = $3;\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int8",
"Int8",
"Text"
]
},
"nullable": []
},
"hash": "51f09f073842a6990535b887d8267fab305c21e4d7703bedbadf405b5c2d7582"
}

View File

@@ -34,8 +34,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -40,8 +40,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE schedule SET\n schedule = $1,\n timezone = $2,\n args = $3,\n on_failure = $4,\n on_failure_times = $5,\n on_failure_exact = $6,\n on_failure_extra_args = $7,\n on_recovery = $8,\n on_recovery_times = $9,\n on_recovery_extra_args = $10,\n on_success = $11,\n on_success_extra_args = $12,\n ws_error_handler_muted = $13,\n retry = $14,\n summary = $15,\n no_flow_overlap = $16,\n tag = $17,\n paused_until = $18,\n path = $19,\n workspace_id = $20,\n cron_version = COALESCE($21, cron_version),\n description = $22,\n dynamic_skip = $23,\n email = $24,\n edited_by = $25,\n permissioned_as = $26,\n labels = COALESCE($27, labels)\n WHERE path = $19 AND workspace_id = $20\n RETURNING\n workspace_id,\n path,\n edited_by,\n edited_at,\n schedule,\n timezone,\n enabled,\n script_path,\n is_flow,\n args AS \"args: _\",\n extra_perms,\n email,\n permissioned_as,\n error,\n on_failure,\n on_failure_times,\n on_failure_exact,\n on_failure_extra_args AS \"on_failure_extra_args: _\",\n on_recovery,\n on_recovery_times,\n on_recovery_extra_args AS \"on_recovery_extra_args: _\",\n on_success,\n on_success_extra_args AS \"on_success_extra_args: _\",\n ws_error_handler_muted,\n retry,\n no_flow_overlap,\n summary,\n description,\n tag,\n paused_until,\n cron_version,\n dynamic_skip,\n labels\n ",
"query": "\n UPDATE schedule SET\n schedule = $1,\n timezone = $2,\n args = $3,\n on_failure = $4,\n on_failure_times = $5,\n on_failure_exact = $6,\n on_failure_extra_args = $7,\n on_recovery = $8,\n on_recovery_times = $9,\n on_recovery_extra_args = $10,\n on_success = $11,\n on_success_extra_args = $12,\n ws_error_handler_muted = $13,\n retry = $14,\n summary = $15,\n no_flow_overlap = $16,\n tag = $17,\n paused_until = $18,\n path = $19,\n workspace_id = $20,\n cron_version = COALESCE($21, cron_version),\n description = $22,\n dynamic_skip = $23,\n email = $24,\n edited_by = $25,\n permissioned_as = $26\n WHERE path = $19 AND workspace_id = $20\n RETURNING\n workspace_id,\n path,\n edited_by,\n edited_at,\n schedule,\n timezone,\n enabled,\n script_path,\n is_flow,\n args AS \"args: _\",\n extra_perms,\n email,\n permissioned_as,\n error,\n on_failure,\n on_failure_times,\n on_failure_exact,\n on_failure_extra_args AS \"on_failure_extra_args: _\",\n on_recovery,\n on_recovery_times,\n on_recovery_extra_args AS \"on_recovery_extra_args: _\",\n on_success,\n on_success_extra_args AS \"on_success_extra_args: _\",\n ws_error_handler_muted,\n retry,\n no_flow_overlap,\n summary,\n description,\n tag,\n paused_until,\n cron_version,\n dynamic_skip\n ",
"describe": {
"columns": [
{
@@ -162,11 +162,6 @@
"ordinal": 31,
"name": "dynamic_skip",
"type_info": "Varchar"
},
{
"ordinal": 32,
"name": "labels",
"type_info": "TextArray"
}
],
"parameters": {
@@ -196,8 +191,7 @@
"Varchar",
"Varchar",
"Varchar",
"Varchar",
"TextArray"
"Varchar"
]
},
"nullable": [
@@ -232,9 +226,8 @@
true,
true,
true,
true,
true
]
},
"hash": "bd2609f999054c5a2a85f2aafe4005bc22731c27f0bf27b3b06ec426a05eda2e"
"hash": "54b4c762add9b1ebfdb2a6d5abd6d20e86dc0e6544f0bb22fa4ec68aa54a4dc8"
}

View File

@@ -148,8 +148,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -43,8 +43,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO flow\n (workspace_id, path, summary, description, archived, extra_perms, dependency_job, draft_only, tag, ws_error_handler_muted, dedicated_worker, timeout, visible_to_runner_only, on_behalf_of_email, concurrency_key, versions, value, schema, edited_by, edited_at)\n SELECT workspace_id, $1, summary, description, archived, extra_perms, dependency_job, draft_only, tag, ws_error_handler_muted, dedicated_worker, timeout, visible_to_runner_only, on_behalf_of_email, concurrency_key, versions, value, schema, edited_by, edited_at\n FROM flow\n WHERE path = $2 AND workspace_id = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "676c758d9c4492dada50edd3ad06dc628e2ba56eab5e1a50c99481da9793759e"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO websocket_trigger (\n workspace_id,\n path,\n url,\n script_path,\n is_flow,\n mode,\n filters,\n filter_logic,\n initial_messages,\n url_runnable_args,\n edited_by,\n can_return_message,\n can_return_error_result,\n permissioned_as,\n edited_at,\n error_handler_path,\n error_handler_args,\n retry,\n heartbeat\n ) VALUES (\n $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, now(), $15, $16, $17, $18\n )\n ",
"query": "\n INSERT INTO websocket_trigger (\n workspace_id,\n path,\n url,\n script_path,\n is_flow,\n mode,\n filters,\n filter_logic,\n initial_messages,\n url_runnable_args,\n edited_by,\n can_return_message,\n can_return_error_result,\n permissioned_as,\n edited_at,\n error_handler_path,\n error_handler_args,\n retry\n ) VALUES (\n $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, now(), $15, $16, $17\n )\n ",
"describe": {
"columns": [],
"parameters": {
@@ -32,11 +32,10 @@
"Varchar",
"Varchar",
"Jsonb",
"Jsonb",
"Jsonb"
]
},
"nullable": []
},
"hash": "11fd92de8688ef6b4d524aade507850a9cb3e097f2d957219d04ad134a5e0399"
"hash": "6948eb5aabf82f2f4a08dd4410eb472080ecab3ed652912397245e5216ae0389"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO app\n (workspace_id, path, summary, policy, versions, draft_only, custom_path, labels)\n VALUES ($1, $2, $3, $4, '{}', $5, $6, $7) RETURNING id",
"query": "INSERT INTO app\n (workspace_id, path, summary, policy, versions, draft_only, custom_path)\n VALUES ($1, $2, $3, $4, '{}', $5, $6) RETURNING id",
"describe": {
"columns": [
{
@@ -16,13 +16,12 @@
"Varchar",
"Jsonb",
"Bool",
"Text",
"TextArray"
"Text"
]
},
"nullable": [
false
]
},
"hash": "e4836a1ee97e4723bddc28b94e23a54b6aa1f458f3ecca8f35432153e54b143d"
"hash": "6b53f7c4bb73177316d6134698f3979f51b53dcd4d8ec50d312c9e7fe31ad5f5"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO flow (\n workspace_id, path, summary, description,\n dependency_job, lock_error_logs, draft_only, tag,\n dedicated_worker, visible_to_runner_only, on_behalf_of_email,\n ws_error_handler_muted,\n value, schema, edited_by, edited_at, labels\n ) VALUES (\n $1, $2, $3, $4,\n NULL, '', $5, $6,\n $7, $8, $9,\n $10,\n $11, $12::text::json, $13, now(), $14\n )",
"query": "INSERT INTO flow (\n workspace_id, path, summary, description,\n dependency_job, lock_error_logs, draft_only, tag,\n dedicated_worker, visible_to_runner_only, on_behalf_of_email,\n ws_error_handler_muted,\n value, schema, edited_by, edited_at\n ) VALUES (\n $1, $2, $3, $4,\n NULL, '', $5, $6,\n $7, $8, $9,\n $10,\n $11, $12::text::json, $13, now()\n )",
"describe": {
"columns": [],
"parameters": {
@@ -17,11 +17,10 @@
"Bool",
"Jsonb",
"Text",
"Varchar",
"TextArray"
"Varchar"
]
},
"nullable": []
},
"hash": "b6f95b3fd1d0431d96d0409424dbb20cb3020f93454978d078082482b86cbebe"
"hash": "6bde827da007b470b9d0acccfc3e00ce6aac650b9138a236f34c614eed753849"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE\n flow\n SET\n path = $1,\n summary = $2,\n description = $3,\n dependency_job = NULL,\n lock_error_logs = '',\n draft_only = NULL,\n tag = $4,\n dedicated_worker = $5,\n visible_to_runner_only = $6,\n on_behalf_of_email = $7,\n ws_error_handler_muted = $8,\n value = $9,\n schema = $10::text::json,\n edited_by = $11,\n edited_at = now(),\n labels = COALESCE($14, labels)\n WHERE\n path = $12 AND workspace_id = $13",
"query": "\n UPDATE\n flow\n SET\n path = $1,\n summary = $2,\n description = $3,\n dependency_job = NULL,\n lock_error_logs = '',\n draft_only = NULL,\n tag = $4,\n dedicated_worker = $5,\n visible_to_runner_only = $6,\n on_behalf_of_email = $7,\n ws_error_handler_muted = $8,\n value = $9,\n schema = $10::text::json,\n edited_by = $11,\n edited_at = now()\n WHERE\n path = $12 AND workspace_id = $13",
"describe": {
"columns": [],
"parameters": {
@@ -17,11 +17,10 @@
"Text",
"Varchar",
"Text",
"Text",
"TextArray"
"Text"
]
},
"nullable": []
},
"hash": "c06796e8647cf278c6e0809562aaaa872403890eae3e606f379343671c2fff02"
"hash": "77ac7257be02fb04c4b3213e2221e6f60621b4b2909d770de744ef5671e12ed9"
}

View File

@@ -1,14 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO notify_event (channel, payload) VALUES ('restart_worker_group', $1)",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text"
]
},
"nullable": []
},
"hash": "78f7c4efd7be2aad03f0ec67ab882e1f9aaa7141ab75046a71ac789ab659bdc6"
}

View File

@@ -76,8 +76,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE http_trigger SET labels = $1 WHERE workspace_id = $2 AND path = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"TextArray",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "86c0ef92652085b93979a8836bedb33a366a84426a115c75f58dcc43ab91705e"
}

View File

@@ -41,8 +41,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -153,8 +153,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -118,8 +118,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "select hash, tag, concurrency_key, concurrent_limit, concurrency_time_window_s, debounce_key, debounce_delay_s, cache_ttl, cache_ignore_s3_path, runnable_settings_handle, language as \"language: ScriptLang\", dedicated_worker, priority, timeout, on_behalf_of_email, created_by, labels FROM script\n WHERE path = $1 AND workspace_id = $2 AND archived = false AND (lock IS NOT NULL OR $3 = false)\n ORDER BY created_at DESC LIMIT 1",
"query": "select hash, tag, concurrency_key, concurrent_limit, concurrency_time_window_s, debounce_key, debounce_delay_s, cache_ttl, cache_ignore_s3_path, runnable_settings_handle, language as \"language: ScriptLang\", dedicated_worker, priority, timeout, on_behalf_of_email, created_by FROM script\n WHERE path = $1 AND workspace_id = $2 AND archived = false AND (lock IS NOT NULL OR $3 = false)\n ORDER BY created_at DESC LIMIT 1",
"describe": {
"columns": [
{
@@ -83,8 +83,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}
@@ -114,11 +113,6 @@
"ordinal": 15,
"name": "created_by",
"type_info": "Varchar"
},
{
"ordinal": 16,
"name": "labels",
"type_info": "TextArray"
}
],
"parameters": {
@@ -144,9 +138,8 @@
true,
true,
true,
false,
true
false
]
},
"hash": "71767e6684957af5dff56a1bb64f980f712f92798d11feaeb0832962ad9ddb2e"
"hash": "a33673ebc4d1eb4c3513987dbc43e2c80974598e1d9fe7203145bfc29928ba65"
}

View File

@@ -133,8 +133,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -38,8 +38,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO script\n (workspace_id, hash, path, parent_hashes, summary, description, content, created_by, schema, is_template, extra_perms, lock, language, kind, tag, draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, cache_ignore_s3_path, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only, auto_kind, codebase, has_preprocessor, on_behalf_of_email, schema_validation, assets, debounce_key, debounce_delay_s, runnable_settings_handle, modules, labels)\n\n SELECT workspace_id, $1, path, array_prepend($2::bigint, COALESCE(parent_hashes, '{}'::bigint[])), summary, description, content, created_by, schema, is_template, extra_perms, NULL, language, kind, tag, draft_only, envs, concurrent_limit, concurrency_time_window_s, cache_ttl, cache_ignore_s3_path, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only, auto_kind, codebase, has_preprocessor, on_behalf_of_email, schema_validation, assets, debounce_key, debounce_delay_s, runnable_settings_handle, modules, labels\n\n FROM script WHERE hash = $2 AND workspace_id = $3;\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Int8",
"Int8",
"Text"
]
},
"nullable": []
},
"hash": "a969194571dd3f12e628ce0f01b0ddc09bbcf4506eff2290664c295d16fec4ae"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE schedule SET\n enabled = $1,\n email = $2\n WHERE path = $3 AND workspace_id = $4\n RETURNING\n workspace_id,\n path,\n edited_by,\n edited_at,\n schedule,\n timezone,\n enabled,\n script_path,\n is_flow,\n args AS \"args: _\",\n extra_perms,\n email,\n permissioned_as,\n error,\n on_failure,\n on_failure_times,\n on_failure_exact,\n on_failure_extra_args AS \"on_failure_extra_args: _\",\n on_recovery,\n on_recovery_times,\n on_recovery_extra_args AS \"on_recovery_extra_args: _\",\n on_success,\n on_success_extra_args AS \"on_success_extra_args: _\",\n ws_error_handler_muted,\n retry,\n no_flow_overlap,\n summary,\n description,\n tag,\n paused_until,\n cron_version,\n dynamic_skip,\n labels\n ",
"query": "\n UPDATE schedule SET\n enabled = $1,\n email = $2\n WHERE path = $3 AND workspace_id = $4\n RETURNING\n workspace_id,\n path,\n edited_by,\n edited_at,\n schedule,\n timezone,\n enabled,\n script_path,\n is_flow,\n args AS \"args: _\",\n extra_perms,\n email,\n permissioned_as,\n error,\n on_failure,\n on_failure_times,\n on_failure_exact,\n on_failure_extra_args AS \"on_failure_extra_args: _\",\n on_recovery,\n on_recovery_times,\n on_recovery_extra_args AS \"on_recovery_extra_args: _\",\n on_success,\n on_success_extra_args AS \"on_success_extra_args: _\",\n ws_error_handler_muted,\n retry,\n no_flow_overlap,\n summary,\n description,\n tag,\n paused_until,\n cron_version,\n dynamic_skip\n ",
"describe": {
"columns": [
{
@@ -162,11 +162,6 @@
"ordinal": 31,
"name": "dynamic_skip",
"type_info": "Varchar"
},
{
"ordinal": 32,
"name": "labels",
"type_info": "TextArray"
}
],
"parameters": {
@@ -209,9 +204,8 @@
true,
true,
true,
true,
true
]
},
"hash": "642ca096c1c151fc01445593c8d2ed879a9a7be6ff044a9ce1b581ba725665fe"
"hash": "ad96768ff61fab1cfb9421683bb13b64f5f157fafe114d50fb910dc36ebe0f91"
}

View File

@@ -153,8 +153,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -123,8 +123,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -43,8 +43,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE app SET labels = $1 WHERE path = $2 AND workspace_id = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"TextArray",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "b657b718ec381fbb1d41841c88118b88c4d7ea8f0cde663ed8f8226faf75b0f6"
}

View File

@@ -1,22 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT DISTINCT unnest(labels) as \"label!\" FROM (\n SELECT labels FROM script WHERE workspace_id = $1 AND labels IS NOT NULL\n UNION ALL SELECT labels FROM flow WHERE workspace_id = $1 AND labels IS NOT NULL\n UNION ALL SELECT labels FROM resource WHERE workspace_id = $1 AND labels IS NOT NULL\n UNION ALL SELECT labels FROM variable WHERE workspace_id = $1 AND labels IS NOT NULL\n UNION ALL SELECT labels FROM schedule WHERE workspace_id = $1 AND labels IS NOT NULL\n UNION ALL SELECT labels FROM app WHERE workspace_id = $1 AND labels IS NOT NULL\n ) t ORDER BY 1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "label!",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
null
]
},
"hash": "b782179261b4054289a1a595f6e06ee2035ae9811bc49abce903a04439baf800"
}

View File

@@ -40,8 +40,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -77,8 +77,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -1,23 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT value AS \"value!: Json<Box<RawValue>>\" FROM flow WHERE path = $1 AND workspace_id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "value!: Json<Box<RawValue>>",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
false
]
},
"hash": "c569535d4aded82ffef5e5066e24948c8fcdb8d36913775449b982782c8583e9"
}

View File

@@ -68,8 +68,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -77,8 +77,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n INSERT INTO schedule (\n workspace_id, path, schedule, timezone, edited_by, script_path,\n is_flow, args, enabled, email, permissioned_as,\n on_failure, on_failure_times, on_failure_exact, on_failure_extra_args,\n on_recovery, on_recovery_times, on_recovery_extra_args,\n on_success, on_success_extra_args,\n ws_error_handler_muted, retry, summary, no_flow_overlap,\n tag, paused_until, cron_version, description, dynamic_skip, labels\n ) VALUES (\n $1, $2, $3, $4, $5, $6,\n $7, $8, $9, $10, $11,\n $12, $13, $14, $15,\n $16, $17, $18,\n $19, $20,\n $21, $22, $23, $24,\n $25, $26, $27, $28, $29, $30\n )\n RETURNING\n workspace_id,\n path,\n edited_by,\n edited_at,\n schedule,\n timezone,\n enabled,\n script_path,\n is_flow,\n args AS \"args: _\",\n extra_perms,\n email,\n permissioned_as,\n error,\n on_failure,\n on_failure_times,\n on_failure_exact,\n on_failure_extra_args AS \"on_failure_extra_args: _\",\n on_recovery,\n on_recovery_times,\n on_recovery_extra_args AS \"on_recovery_extra_args: _\",\n on_success,\n on_success_extra_args AS \"on_success_extra_args: _\",\n ws_error_handler_muted,\n retry,\n no_flow_overlap,\n summary,\n description,\n tag,\n paused_until,\n cron_version,\n dynamic_skip,\n labels\n ",
"query": "\n INSERT INTO schedule (\n workspace_id, path, schedule, timezone, edited_by, script_path,\n is_flow, args, enabled, email, permissioned_as,\n on_failure, on_failure_times, on_failure_exact, on_failure_extra_args,\n on_recovery, on_recovery_times, on_recovery_extra_args,\n on_success, on_success_extra_args,\n ws_error_handler_muted, retry, summary, no_flow_overlap,\n tag, paused_until, cron_version, description, dynamic_skip\n ) VALUES (\n $1, $2, $3, $4, $5, $6,\n $7, $8, $9, $10, $11,\n $12, $13, $14, $15,\n $16, $17, $18,\n $19, $20,\n $21, $22, $23, $24,\n $25, $26, $27, $28, $29\n )\n RETURNING\n workspace_id,\n path,\n edited_by,\n edited_at,\n schedule,\n timezone,\n enabled,\n script_path,\n is_flow,\n args AS \"args: _\",\n extra_perms,\n email,\n permissioned_as,\n error,\n on_failure,\n on_failure_times,\n on_failure_exact,\n on_failure_extra_args AS \"on_failure_extra_args: _\",\n on_recovery,\n on_recovery_times,\n on_recovery_extra_args AS \"on_recovery_extra_args: _\",\n on_success,\n on_success_extra_args AS \"on_success_extra_args: _\",\n ws_error_handler_muted,\n retry,\n no_flow_overlap,\n summary,\n description,\n tag,\n paused_until,\n cron_version,\n dynamic_skip\n ",
"describe": {
"columns": [
{
@@ -162,11 +162,6 @@
"ordinal": 31,
"name": "dynamic_skip",
"type_info": "Varchar"
},
{
"ordinal": 32,
"name": "labels",
"type_info": "TextArray"
}
],
"parameters": {
@@ -199,8 +194,7 @@
"Timestamptz",
"Text",
"Text",
"Varchar",
"TextArray"
"Varchar"
]
},
"nullable": [
@@ -235,9 +229,8 @@
true,
true,
true,
true,
true
]
},
"hash": "2effe885aafaa0c5fc1f969b8c6ffbd38c53fb586251ba780b75a007e5a47ed6"
"hash": "dd20f94d560238096390371c98ded1f80825a11cd61c0bb431678ad9ab4a138e"
}

View File

@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO flow\n (workspace_id, path, summary, description, archived, extra_perms, dependency_job, draft_only, tag, ws_error_handler_muted, dedicated_worker, timeout, visible_to_runner_only, on_behalf_of_email, concurrency_key, versions, value, schema, edited_by, edited_at, labels)\n SELECT workspace_id, $1, summary, description, archived, extra_perms, dependency_job, draft_only, tag, ws_error_handler_muted, dedicated_worker, timeout, visible_to_runner_only, on_behalf_of_email, concurrency_key, versions, value, schema, edited_by, edited_at, labels\n FROM flow\n WHERE path = $2 AND workspace_id = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "ddda19024473b4e5b1d450bf56c667056f6b3696dea7d73758e53f825bfce13e"
}

View File

@@ -1,20 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "INSERT INTO resource\n (workspace_id, path, value, description, resource_type, created_by, edited_at, labels)\n VALUES ($1, $2, $3, $4, $5, $6, now(), $7) ON CONFLICT (workspace_id, path)\n DO UPDATE SET value = EXCLUDED.value, description = EXCLUDED.description, resource_type = EXCLUDED.resource_type, edited_at = now(), labels = EXCLUDED.labels",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Varchar",
"Jsonb",
"Text",
"Varchar",
"Varchar",
"TextArray"
]
},
"nullable": []
},
"hash": "deac41298e8b0d0870e314fef0813c24dd55d63bda78a0a5f35ed6f22bea6bef"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE\n websocket_trigger\n SET\n url = $1,\n script_path = $2,\n path = $3,\n is_flow = $4,\n filters = $5,\n filter_logic = $6,\n initial_messages = $7,\n url_runnable_args = $8,\n edited_by = $9,\n permissioned_as = $10,\n can_return_message = $11,\n can_return_error_result = $12,\n edited_at = now(),\n server_id = NULL,\n error = NULL,\n error_handler_path = $15,\n error_handler_args = $16,\n retry = $17,\n heartbeat = $18\n WHERE\n workspace_id = $13 AND path = $14\n ",
"query": "\n UPDATE\n websocket_trigger\n SET\n url = $1,\n script_path = $2,\n path = $3,\n is_flow = $4,\n filters = $5,\n filter_logic = $6,\n initial_messages = $7,\n url_runnable_args = $8,\n edited_by = $9,\n permissioned_as = $10,\n can_return_message = $11,\n can_return_error_result = $12,\n edited_at = now(),\n server_id = NULL,\n error = NULL,\n error_handler_path = $15,\n error_handler_args = $16,\n retry = $17\n WHERE\n workspace_id = $13 AND path = $14\n ",
"describe": {
"columns": [],
"parameters": {
@@ -21,11 +21,10 @@
"Text",
"Varchar",
"Jsonb",
"Jsonb",
"Jsonb"
]
},
"nullable": []
},
"hash": "492edd53e497a45c314d41044e85a5e3492227b5049dc6870d60817ad929e7af"
"hash": "e3d4f89ce36337af15d237b543eaca47771b480ff194884f9c947dcaf71d6cf9"
}

View File

@@ -133,8 +133,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -1,64 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT workspace_id, name, language AS \"language: windmill_common::scripts::ScriptLang\"\n FROM workspace_dependencies\n WHERE archived = false\n ORDER BY workspace_id, name",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "name",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "language: windmill_common::scripts::ScriptLang",
"type_info": {
"Custom": {
"name": "script_lang",
"kind": {
"Enum": [
"python3",
"deno",
"go",
"bash",
"postgresql",
"nativets",
"bun",
"mysql",
"bigquery",
"snowflake",
"graphql",
"powershell",
"mssql",
"php",
"bunnative",
"rust",
"ansible",
"csharp",
"oracledb",
"nu",
"java",
"duckdb",
"ruby",
"rlang"
]
}
}
}
}
],
"parameters": {
"Left": []
},
"nullable": [
false,
true,
false
]
},
"hash": "edd6c09b7f012588788fd3c572d20eb439a80d52ae75ebd25128ffce759cd313"
}

View File

@@ -1,72 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT DISTINCT ON (workspace_id, path)\n workspace_id, path, language AS \"language: windmill_common::scripts::ScriptLang\", content\n FROM script\n WHERE archived = false\n AND dedicated_worker = true\n AND language = ANY($1::text[]::SCRIPT_LANG[])\n ORDER BY workspace_id, path, created_at DESC",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "path",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "language: windmill_common::scripts::ScriptLang",
"type_info": {
"Custom": {
"name": "script_lang",
"kind": {
"Enum": [
"python3",
"deno",
"go",
"bash",
"postgresql",
"nativets",
"bun",
"mysql",
"bigquery",
"snowflake",
"graphql",
"powershell",
"mssql",
"php",
"bunnative",
"rust",
"ansible",
"csharp",
"oracledb",
"nu",
"java",
"duckdb",
"ruby",
"rlang"
]
}
}
}
},
{
"ordinal": 3,
"name": "content",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"TextArray"
]
},
"nullable": [
false,
false,
false,
false
]
},
"hash": "f0858450021df721d8a48b1b5dc887c5424562acd9769c80c5899193ef16b56b"
}

View File

@@ -40,8 +40,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -38,8 +38,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}
@@ -85,8 +84,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -33,8 +33,7 @@
"nu",
"java",
"duckdb",
"ruby",
"rlang"
"ruby"
]
}
}

View File

@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE resource SET labels = $1 WHERE path = $2 AND workspace_id = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"TextArray",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "f6f850c419771b193f506ceca63de805cbe6bdee314ca40d912010db307bd13e"
}

296
backend/Cargo.lock generated
View File

@@ -2108,7 +2108,7 @@ dependencies = [
"rayon",
"safetensors",
"thiserror 2.0.18",
"yoke 0.8.2",
"yoke 0.8.1",
"zip",
]
@@ -2373,9 +2373,9 @@ dependencies = [
[[package]]
name = "cmov"
version = "0.5.3"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746"
checksum = "de0758edba32d61d1fd9f4d69491b47604b91ee2f7e6b33de7e54ca4ebe55dc3"
[[package]]
name = "codespan-reporting"
@@ -2805,9 +2805,9 @@ dependencies = [
[[package]]
name = "ctutils"
version = "0.4.2"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e"
checksum = "1005a6d4446f5120ef475ad3d2af2b30c49c2c9c6904258e3bb30219bebed5e4"
dependencies = [
"cmov",
]
@@ -7224,23 +7224,22 @@ dependencies = [
[[package]]
name = "icu_collections"
version = "2.2.0"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c"
checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"
dependencies = [
"displaydoc",
"potential_utf",
"utf8_iter",
"yoke 0.8.2",
"yoke 0.8.1",
"zerofrom",
"zerovec",
]
[[package]]
name = "icu_locale_core"
version = "2.2.0"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29"
checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"
dependencies = [
"displaydoc",
"litemap",
@@ -7251,9 +7250,9 @@ dependencies = [
[[package]]
name = "icu_normalizer"
version = "2.2.0"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4"
checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599"
dependencies = [
"icu_collections",
"icu_normalizer_data",
@@ -7265,15 +7264,15 @@ dependencies = [
[[package]]
name = "icu_normalizer_data"
version = "2.2.0"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38"
checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
[[package]]
name = "icu_properties"
version = "2.2.0"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de"
checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
dependencies = [
"icu_collections",
"icu_locale_core",
@@ -7285,20 +7284,20 @@ dependencies = [
[[package]]
name = "icu_properties_data"
version = "2.2.0"
version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14"
checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
[[package]]
name = "icu_provider"
version = "2.2.0"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421"
checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614"
dependencies = [
"displaydoc",
"icu_locale_core",
"writeable",
"yoke 0.8.2",
"yoke 0.8.1",
"zerofrom",
"zerotrie",
"zerovec",
@@ -8047,9 +8046,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.184"
version = "0.2.183"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af"
checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
[[package]]
name = "libffi"
@@ -8205,9 +8204,9 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
[[package]]
name = "litemap"
version = "0.8.2"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0"
checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77"
[[package]]
name = "litrs"
@@ -10428,9 +10427,9 @@ dependencies = [
[[package]]
name = "potential_utf"
version = "0.1.5"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564"
checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77"
dependencies = [
"zerovec",
]
@@ -12118,15 +12117,6 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ece8e78b2f38ec51c51f5d475df0a7187ba5111b2a28bdc761ee05b075d40a71"
[[package]]
name = "scc"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46e6f046b7fef48e2660c57ed794263155d713de679057f2d0c169bfc6e756cc"
dependencies = [
"sdd",
]
[[package]]
name = "schannel"
version = "0.1.29"
@@ -12232,12 +12222,6 @@ dependencies = [
"untrusted 0.9.0",
]
[[package]]
name = "sdd"
version = "3.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "490dcfcbfef26be6800d11870ff2df8774fa6e86d047e3e8c8a76b25655e41ca"
[[package]]
name = "seahash"
version = "4.1.0"
@@ -12574,32 +12558,6 @@ dependencies = [
"serde",
]
[[package]]
name = "serial_test"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "911bd979bf1070a3f3aa7b691a3b3e9968f339ceeec89e08c280a8a22207a32f"
dependencies = [
"futures-executor",
"futures-util",
"log",
"once_cell",
"parking_lot",
"scc",
"serial_test_derive",
]
[[package]]
name = "serial_test_derive"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a7d91949b85b0d2fb687445e448b40d322b6b3e4af6b44a29b21d9a5f33e6d9"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.117",
]
[[package]]
name = "sha1"
version = "0.10.6"
@@ -14277,9 +14235,9 @@ dependencies = [
[[package]]
name = "tinystr"
version = "0.8.3"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d"
checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869"
dependencies = [
"displaydoc",
"zerovec",
@@ -14667,9 +14625,9 @@ dependencies = [
[[package]]
name = "toml_parser"
version = "1.1.2+spec-1.1.0"
version = "1.1.1+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526"
checksum = "39ca317ebc49f06bd748bfba29533eac9485569dc9bf80b849024b025e814fb9"
dependencies = [
"winnow 1.0.1",
]
@@ -15983,7 +15941,7 @@ dependencies = [
[[package]]
name = "windmill"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"async-nats",
@@ -16012,7 +15970,6 @@ dependencies = [
"serde_derive",
"serde_json",
"serde_yml",
"serial_test",
"sha1",
"sha2 0.10.9",
"sql-builder",
@@ -16062,7 +16019,7 @@ dependencies = [
[[package]]
name = "windmill-alerting"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16075,7 +16032,7 @@ dependencies = [
[[package]]
name = "windmill-api"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"argon2",
@@ -16216,7 +16173,7 @@ dependencies = [
[[package]]
name = "windmill-api-agent-workers"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16239,7 +16196,7 @@ dependencies = [
[[package]]
name = "windmill-api-assets"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16252,7 +16209,7 @@ dependencies = [
[[package]]
name = "windmill-api-auth"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"axum 0.8.4",
@@ -16278,7 +16235,7 @@ dependencies = [
[[package]]
name = "windmill-api-client"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"reqwest 0.12.28",
"serde",
@@ -16288,7 +16245,7 @@ dependencies = [
[[package]]
name = "windmill-api-configs"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16305,7 +16262,7 @@ dependencies = [
[[package]]
name = "windmill-api-debug"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"axum 0.8.4",
"base64 0.22.1",
@@ -16328,7 +16285,7 @@ dependencies = [
[[package]]
name = "windmill-api-embeddings"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"axum 0.8.4",
@@ -16351,7 +16308,7 @@ dependencies = [
[[package]]
name = "windmill-api-flow-conversations"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16367,7 +16324,7 @@ dependencies = [
[[package]]
name = "windmill-api-flows"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16387,7 +16344,7 @@ dependencies = [
[[package]]
name = "windmill-api-groups"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16407,7 +16364,7 @@ dependencies = [
[[package]]
name = "windmill-api-inputs"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16421,7 +16378,7 @@ dependencies = [
[[package]]
name = "windmill-api-integration-tests"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"async-nats",
@@ -16452,7 +16409,7 @@ dependencies = [
[[package]]
name = "windmill-api-jobs"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"axum 0.8.4",
@@ -16477,7 +16434,7 @@ dependencies = [
[[package]]
name = "windmill-api-npm-proxy"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"axum 0.8.4",
"flate2",
@@ -16495,7 +16452,7 @@ dependencies = [
[[package]]
name = "windmill-api-openapi"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"axum 0.8.4",
@@ -16517,7 +16474,7 @@ dependencies = [
[[package]]
name = "windmill-api-schedule"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16537,7 +16494,7 @@ dependencies = [
[[package]]
name = "windmill-api-scripts"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16567,7 +16524,7 @@ dependencies = [
[[package]]
name = "windmill-api-settings"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"axum 0.8.4",
@@ -16594,7 +16551,7 @@ dependencies = [
[[package]]
name = "windmill-api-sse"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"lazy_static",
"serde",
@@ -16606,7 +16563,7 @@ dependencies = [
[[package]]
name = "windmill-api-users"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"argon2",
"axum 0.8.4",
@@ -16631,7 +16588,7 @@ dependencies = [
[[package]]
name = "windmill-api-workers"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16645,7 +16602,7 @@ dependencies = [
[[package]]
name = "windmill-api-workspaces"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"axum 0.8.4",
"chrono",
@@ -16677,7 +16634,7 @@ dependencies = [
[[package]]
name = "windmill-audit"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"chrono",
"lazy_static",
@@ -16691,7 +16648,7 @@ dependencies = [
[[package]]
name = "windmill-autoscaling"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"axum 0.8.4",
@@ -16710,7 +16667,7 @@ dependencies = [
[[package]]
name = "windmill-common"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"aes-gcm",
"aho-corasick",
@@ -16812,7 +16769,7 @@ dependencies = [
[[package]]
name = "windmill-dep-map"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"chrono",
"itertools 0.14.0",
@@ -16831,7 +16788,7 @@ dependencies = [
[[package]]
name = "windmill-git-sync"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"regex",
"serde",
@@ -16846,7 +16803,7 @@ dependencies = [
[[package]]
name = "windmill-indexer"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"astral-tokio-tar",
@@ -16870,7 +16827,7 @@ dependencies = [
[[package]]
name = "windmill-jseval"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"futures",
@@ -16887,7 +16844,7 @@ dependencies = [
[[package]]
name = "windmill-macros"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"itertools 0.14.0",
"lazy_static",
@@ -16903,7 +16860,7 @@ dependencies = [
[[package]]
name = "windmill-mcp"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"async-trait",
@@ -16924,7 +16881,7 @@ dependencies = [
[[package]]
name = "windmill-native-triggers"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"async-trait",
@@ -16955,7 +16912,7 @@ dependencies = [
[[package]]
name = "windmill-oauth"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"async-oauth2",
@@ -16979,7 +16936,7 @@ dependencies = [
[[package]]
name = "windmill-object-store"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"async-stream",
@@ -17013,7 +16970,7 @@ dependencies = [
[[package]]
name = "windmill-operator"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"futures",
@@ -17031,7 +16988,7 @@ dependencies = [
[[package]]
name = "windmill-parser"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"convert_case 0.6.0",
"serde",
@@ -17040,7 +16997,7 @@ dependencies = [
[[package]]
name = "windmill-parser-bash"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"lazy_static",
@@ -17052,7 +17009,7 @@ dependencies = [
[[package]]
name = "windmill-parser-csharp"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"serde_json",
@@ -17064,7 +17021,7 @@ dependencies = [
[[package]]
name = "windmill-parser-go"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"gosyn",
@@ -17076,7 +17033,7 @@ dependencies = [
[[package]]
name = "windmill-parser-graphql"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"lazy_static",
@@ -17088,7 +17045,7 @@ dependencies = [
[[package]]
name = "windmill-parser-java"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"serde_json",
@@ -17100,7 +17057,7 @@ dependencies = [
[[package]]
name = "windmill-parser-nu"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"nu-parser",
@@ -17111,7 +17068,7 @@ dependencies = [
[[package]]
name = "windmill-parser-php"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"itertools 0.14.0",
@@ -17122,7 +17079,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"itertools 0.14.0",
@@ -17134,7 +17091,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py-asset"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"rustpython-ast",
@@ -17145,7 +17102,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py-imports"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"async-recursion",
@@ -17167,7 +17124,7 @@ dependencies = [
[[package]]
name = "windmill-parser-r"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"serde_json",
@@ -17179,7 +17136,7 @@ dependencies = [
[[package]]
name = "windmill-parser-ruby"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"lazy_static",
@@ -17193,7 +17150,7 @@ dependencies = [
[[package]]
name = "windmill-parser-rust"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"convert_case 0.6.0",
@@ -17210,7 +17167,7 @@ dependencies = [
[[package]]
name = "windmill-parser-sql"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"lazy_static",
@@ -17223,7 +17180,7 @@ dependencies = [
[[package]]
name = "windmill-parser-sql-asset"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"serde",
@@ -17235,7 +17192,7 @@ dependencies = [
[[package]]
name = "windmill-parser-ts"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"lazy_static",
@@ -17253,7 +17210,7 @@ dependencies = [
[[package]]
name = "windmill-parser-ts-asset"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"serde-wasm-bindgen",
@@ -17269,7 +17226,7 @@ dependencies = [
[[package]]
name = "windmill-parser-wac"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"rustpython-ast",
@@ -17285,7 +17242,7 @@ dependencies = [
[[package]]
name = "windmill-parser-yaml"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"serde",
@@ -17296,7 +17253,7 @@ dependencies = [
[[package]]
name = "windmill-queue"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"async-recursion",
@@ -17333,7 +17290,7 @@ dependencies = [
[[package]]
name = "windmill-runtime-nativets"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"const_format",
@@ -17371,7 +17328,7 @@ dependencies = [
[[package]]
name = "windmill-sql-datatype-parser-wasm"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"getrandom 0.3.4",
"wasm-bindgen",
@@ -17382,7 +17339,7 @@ dependencies = [
[[package]]
name = "windmill-store"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"async-recursion",
@@ -17411,7 +17368,7 @@ dependencies = [
[[package]]
name = "windmill-test-utils"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17435,7 +17392,7 @@ dependencies = [
[[package]]
name = "windmill-trigger"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17468,7 +17425,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-email"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17488,7 +17445,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-gcp"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17522,7 +17479,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-http"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17558,7 +17515,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-kafka"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17581,7 +17538,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-mqtt"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17605,7 +17562,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-nats"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"async-nats",
@@ -17629,7 +17586,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-postgres"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17664,7 +17621,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-sqs"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17692,7 +17649,7 @@ dependencies = [
[[package]]
name = "windmill-trigger-websocket"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"async-trait",
@@ -17715,7 +17672,7 @@ dependencies = [
[[package]]
name = "windmill-types"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"bitflags 2.9.4",
@@ -17734,7 +17691,7 @@ dependencies = [
[[package]]
name = "windmill-worker"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"anyhow",
"async-once-cell",
@@ -17838,14 +17795,13 @@ dependencies = [
"windmill-runtime-nativets",
"windmill-types",
"windmill-worker-volumes",
"windows 0.61.3",
"x509-parser 0.16.0",
"yaml-rust",
]
[[package]]
name = "windmill-worker-volumes"
version = "1.673.0"
version = "1.672.0"
dependencies = [
"bytes",
"futures",
@@ -18545,9 +18501,9 @@ dependencies = [
[[package]]
name = "writeable"
version = "0.6.3"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4"
checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
[[package]]
name = "wtf8"
@@ -18680,12 +18636,12 @@ dependencies = [
[[package]]
name = "yoke"
version = "0.8.2"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca"
checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954"
dependencies = [
"stable_deref_trait",
"yoke-derive 0.8.2",
"yoke-derive 0.8.1",
"zerofrom",
]
@@ -18703,9 +18659,9 @@ dependencies = [
[[package]]
name = "yoke-derive"
version = "0.8.2"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d"
dependencies = [
"proc-macro2",
"quote",
@@ -18735,18 +18691,18 @@ dependencies = [
[[package]]
name = "zerofrom"
version = "0.1.7"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df"
checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5"
dependencies = [
"zerofrom-derive",
]
[[package]]
name = "zerofrom-derive"
version = "0.1.7"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502"
dependencies = [
"proc-macro2",
"quote",
@@ -18776,31 +18732,31 @@ dependencies = [
[[package]]
name = "zerotrie"
version = "0.2.4"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf"
checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851"
dependencies = [
"displaydoc",
"yoke 0.8.2",
"yoke 0.8.1",
"zerofrom",
]
[[package]]
name = "zerovec"
version = "0.11.6"
version = "0.11.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239"
checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002"
dependencies = [
"yoke 0.8.2",
"yoke 0.8.1",
"zerofrom",
"zerovec-derive",
]
[[package]]
name = "zerovec-derive"
version = "0.11.3"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3"
dependencies = [
"proc-macro2",
"quote",

View File

@@ -1,6 +1,6 @@
[package]
name = "windmill"
version = "1.673.0"
version = "1.672.0"
authors.workspace = true
edition.workspace = true
@@ -85,7 +85,7 @@ members = [
exclude = ["./windmill-duckdb-ffi-internal", "./parsers/windmill-parser-wasm"]
[workspace.package]
version = "1.673.0"
version = "1.672.0"
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
edition = "2021"
@@ -267,7 +267,6 @@ windmill-types.workspace = true
opentelemetry = { workspace = true }
opentelemetry_sdk = { workspace = true }
windmill-trigger.workspace = true
serial_test = "3"
windmill-trigger-websocket.workspace = true
windmill-trigger-postgres.workspace = true
windmill-trigger-mqtt.workspace = true
@@ -578,7 +577,7 @@ async-stream = "^0"
opentelemetry = "0.30.0"
tracing-opentelemetry = "0.31.0"
opentelemetry_sdk = { version = "0.30.0", features = ["rt-tokio", "testing"] }
opentelemetry-otlp = { version = "0.30.0", features = ["grpc-tonic", "tls", "http-proto"] }
opentelemetry-otlp = { version = "0.30.0", features = ["grpc-tonic", "tls"] }
opentelemetry-appender-tracing = "0.30.0"
opentelemetry-semantic-conventions = { version = "0.30.0", features = ["semconv_experimental"] }
opentelemetry-proto = { version = "0.30.0", features = ["with-serde", "gen-tonic"] }

View File

@@ -1 +1 @@
ef37ca96f140dcd553226fac6bce3ef6d57ec03d
e08a87450627bef9013498e40ee93a47bedda7ee

View File

@@ -1,16 +0,0 @@
ALTER TABLE script DROP COLUMN IF EXISTS labels;
ALTER TABLE flow DROP COLUMN IF EXISTS labels;
ALTER TABLE app DROP COLUMN IF EXISTS labels;
ALTER TABLE raw_app DROP COLUMN IF EXISTS labels;
ALTER TABLE schedule DROP COLUMN IF EXISTS labels;
ALTER TABLE http_trigger DROP COLUMN IF EXISTS labels;
ALTER TABLE websocket_trigger DROP COLUMN IF EXISTS labels;
ALTER TABLE kafka_trigger DROP COLUMN IF EXISTS labels;
ALTER TABLE nats_trigger DROP COLUMN IF EXISTS labels;
ALTER TABLE mqtt_trigger DROP COLUMN IF EXISTS labels;
ALTER TABLE postgres_trigger DROP COLUMN IF EXISTS labels;
ALTER TABLE sqs_trigger DROP COLUMN IF EXISTS labels;
ALTER TABLE gcp_trigger DROP COLUMN IF EXISTS labels;
ALTER TABLE email_trigger DROP COLUMN IF EXISTS labels;
ALTER TABLE resource DROP COLUMN IF EXISTS labels;
ALTER TABLE variable DROP COLUMN IF EXISTS labels;

View File

@@ -1,33 +0,0 @@
ALTER TABLE script ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE flow ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE app ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE raw_app ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE schedule ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE http_trigger ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE websocket_trigger ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE kafka_trigger ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE nats_trigger ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE mqtt_trigger ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE postgres_trigger ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE sqs_trigger ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE gcp_trigger ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE email_trigger ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE resource ADD COLUMN IF NOT EXISTS labels text[];
ALTER TABLE variable ADD COLUMN IF NOT EXISTS labels text[];
CREATE INDEX IF NOT EXISTS idx_script_labels ON script USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_flow_labels ON flow USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_app_labels ON app USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_raw_app_labels ON raw_app USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_schedule_labels ON schedule USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_resource_labels ON resource USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_variable_labels ON variable USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_http_trigger_labels ON http_trigger USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_websocket_trigger_labels ON websocket_trigger USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_kafka_trigger_labels ON kafka_trigger USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_nats_trigger_labels ON nats_trigger USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_mqtt_trigger_labels ON mqtt_trigger USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_postgres_trigger_labels ON postgres_trigger USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_sqs_trigger_labels ON sqs_trigger USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_gcp_trigger_labels ON gcp_trigger USING GIN (labels) WHERE labels IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_email_trigger_labels ON email_trigger USING GIN (labels) WHERE labels IS NOT NULL;

View File

@@ -1,6 +0,0 @@
-- Remove the //nodejs annotation that was prepended by the up migration.
-- Only removes it if it's at the very start of the content.
UPDATE script
SET content = regexp_replace(content, E'^//nodejs\n// dedicated workers were previously running in nodejs mode by default, remove this annotation to use bun\n', '')
WHERE language = 'bun'
AND dedicated_worker = true;

View File

@@ -1,10 +0,0 @@
-- Bun dedicated workers were previously forced to run in nodejs mode at runtime.
-- Now that bun is the default again, add the //nodejs annotation to existing
-- bun dedicated scripts that don't already have it, so their behavior is preserved.
UPDATE script
SET content = '//nodejs
// dedicated workers were previously running in nodejs mode by default, remove this annotation to use bun
' || content
WHERE language = 'bun'
AND dedicated_worker = true
AND content !~ '^//\s*nodejs';

View File

@@ -1 +0,0 @@
ALTER TABLE websocket_trigger DROP COLUMN heartbeat;

View File

@@ -1 +0,0 @@
ALTER TABLE websocket_trigger ADD COLUMN heartbeat JSONB NULL;

View File

@@ -22,82 +22,22 @@ pub fn parse_bash_sig(code: &str) -> anyhow::Result<MainArgSignature> {
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
})
} else {
Err(anyhow!("Error parsing bash script".to_string()))
}
}
/// PowerShell common parameter names that are automatically added by [CmdletBinding()].
/// These should be filtered from the parsed signature since they are not user-defined.
const POWERSHELL_COMMON_PARAMS: &[&str] = &[
"verbose",
"debug",
"erroraction",
"errorvariable",
"informationaction",
"informationvariable",
"outvariable",
"outbuffer",
"pipelinevariable",
"warningaction",
"warningvariable",
"whatif",
"confirm",
"progressaction",
];
/// Detects whether the script uses [CmdletBinding()] and whether it declares SupportsShouldProcess.
fn detect_cmdlet_binding(code: &str) -> (bool, bool) {
let attr_region = match extract_powershell_param_block_with_attributes(code, true) {
Some((region, _)) => region,
None => return (false, false),
};
// Strip comment lines to avoid false positives from commented-out [CmdletBinding()]
let uncommented: String = attr_region
.lines()
.filter(|line| !line.trim_start().starts_with('#'))
.collect::<Vec<_>>()
.join("\n");
let lower = uncommented.to_lowercase();
let has_cmd_binding = lower.contains("[cmdletbinding");
let supports_should_process = has_cmd_binding
&& lower.contains("supportsshouldprocess")
&& !lower.contains("supportsshouldprocess=$false")
&& !lower.contains("supportsshouldprocess = $false");
(has_cmd_binding, supports_should_process)
}
pub fn parse_powershell_sig(code: &str) -> anyhow::Result<MainArgSignature> {
let parsed = parse_powershell_file(&code)?;
if let Some(args) = parsed {
let (has_cmd_binding, supports_should_process) = detect_cmdlet_binding(code);
// Filter out common parameters only when CmdletBinding is present
// (without CmdletBinding, $Verbose etc. are regular user-defined parameters)
let args = if has_cmd_binding {
args.into_iter()
.filter(|arg| !POWERSHELL_COMMON_PARAMS.contains(&arg.name.to_lowercase().as_str()))
.collect()
} else {
args
};
if let Some(x) = parsed {
let args = x;
Ok(MainArgSignature {
star_args: false,
star_kwargs: false,
args,
auto_kind: None,
has_preprocessor: None,
has_cmd_binding: if has_cmd_binding { Some(true) } else { None },
supports_should_process: if supports_should_process {
Some(true)
} else {
None
},
..Default::default()
})
} else {
Err(anyhow!("Error parsing powershell script".to_string()))
@@ -156,10 +96,7 @@ fn parse_bash_file(code: &str) -> anyhow::Result<Option<Vec<Arg>>> {
/// This function uses the existing extract_powershell_param_block validation, which already
/// ensures that only comments, whitespace, and attributes appear before param. So we can
/// simply return everything from the beginning to the end of the param block.
pub fn extract_powershell_param_block_with_attributes(
code: &str,
include_attributes: bool,
) -> Option<(&str, &str)> {
pub fn extract_powershell_param_block_with_attributes(code: &str, include_attributes: bool) -> Option<(&str, &str)> {
// First, use the existing function to validate and find the param block
let param_block = extract_powershell_param_block(code, true)?;
@@ -513,15 +450,11 @@ fn parse_powershell_parameters(content: &str) -> anyhow::Result<Vec<Arg>> {
// Check if this is a Parameter attribute with Mandatory (case-insensitive)
let lower = bracket_content.to_lowercase();
if lower.starts_with("parameter(")
|| lower.starts_with("parameter ")
{
if lower.starts_with("parameter(") || lower.starts_with("parameter ") {
// Check for Mandatory (case-insensitive)
if lower.contains("mandatory") {
// Check if it's explicitly set to false
if !lower.contains("mandatory=$false")
&& !lower.contains("mandatory = $false")
{
if !lower.contains("mandatory=$false") && !lower.contains("mandatory = $false") {
is_mandatory = true;
}
}
@@ -538,11 +471,7 @@ fn parse_powershell_parameters(content: &str) -> anyhow::Result<Vec<Arg>> {
// Check if this looks like a type (simple word, possibly with [])
let is_type = !bracket_content.contains('(')
&& !bracket_content.contains('=')
&& (bracket_content
.chars()
.next()
.unwrap_or(' ')
.is_alphabetic()
&& (bracket_content.chars().next().unwrap_or(' ').is_alphabetic()
|| bracket_content.starts_with('['));
if is_type && !found_dollar {
@@ -600,9 +529,7 @@ fn parse_powershell_parameters(content: &str) -> anyhow::Result<Vec<Arg>> {
while let Some((i, ch)) = chars.peek().copied() {
if in_string {
if ch == string_char
&& content.chars().nth(i.saturating_sub(1)) != Some('`')
{
if ch == string_char && content.chars().nth(i.saturating_sub(1)) != Some('`') {
in_string = false;
default_end = i + 1;
chars.next();
@@ -617,9 +544,7 @@ fn parse_powershell_parameters(content: &str) -> anyhow::Result<Vec<Arg>> {
chars.next();
} else if ch == ',' {
break;
} else if ch.is_whitespace()
&& chars.clone().skip(1).next().map(|(_, c)| c) == Some(',')
{
} else if ch.is_whitespace() && chars.clone().skip(1).next().map(|(_, c)| c) == Some(',') {
break;
} else {
default_end = i + 1;
@@ -627,19 +552,12 @@ fn parse_powershell_parameters(content: &str) -> anyhow::Result<Vec<Arg>> {
}
}
default_value =
Some(content[default_start..default_end].trim().to_string());
default_value = Some(content[default_start..default_end].trim().to_string());
}
',' => {
// End of parameter, finalize it
if let Some(name) = var_name.take() {
args.push(finalize_parameter(
name,
type_annotation.take(),
default_value.take(),
is_mandatory,
validate_set.take(),
)?);
args.push(finalize_parameter(name, type_annotation.take(), default_value.take(), is_mandatory, validate_set.take())?);
}
// Reset for next parameter
@@ -658,13 +576,7 @@ fn parse_powershell_parameters(content: &str) -> anyhow::Result<Vec<Arg>> {
// Finalize last parameter
if let Some(name) = var_name {
args.push(finalize_parameter(
name,
type_annotation,
default_value,
is_mandatory,
validate_set,
)?);
args.push(finalize_parameter(name, type_annotation, default_value, is_mandatory, validate_set)?);
}
Ok(args)
@@ -810,8 +722,7 @@ non_required="${5:-}"
}
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
has_preprocessor: None
}
);
@@ -902,19 +813,14 @@ non_required="${5:-}"
Arg {
otyp: Some("string".to_string()), // [string] (last type bracket with Mandatory and ValidateSet)
name: "Message".to_string(),
typ: Typ::Str(Some(vec![
"Green".to_string(),
"Blue".to_string(),
"Red".to_string()
])), // ValidateSet enum
typ: Typ::Str(Some(vec!["Green".to_string(), "Blue".to_string(), "Red".to_string()])), // ValidateSet enum
default: None,
has_default: false, // Required (Mandatory attribute)
oidx: None
}
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
has_preprocessor: None
}
);
Ok(())
@@ -1064,13 +970,19 @@ non_required="${5:-}"
// Valid: CmdletBinding with comments
assert_eq!(
extract_powershell_param_block("# My function\n[CmdletBinding()]\nparam($Name)", false),
extract_powershell_param_block(
"# My function\n[CmdletBinding()]\nparam($Name)",
false
),
Some("$Name")
);
// Valid: CmdletBinding with whitespace variations
assert_eq!(
extract_powershell_param_block("[CmdletBinding()] \n param($Name)", false),
extract_powershell_param_block(
"[CmdletBinding()] \n param($Name)",
false
),
Some("$Name")
);
@@ -1292,32 +1204,17 @@ param(
// Test with CmdletBinding with parameters
let code3 = "[CmdletBinding(DefaultParameterSetName='ByName')]\nparam($Name, $Id)";
let result3 = extract_powershell_param_block_with_attributes(code3, true);
assert_eq!(
result3,
Some((
"[CmdletBinding(DefaultParameterSetName='ByName')]\nparam($Name, $Id)",
""
))
);
assert_eq!(result3, Some(("[CmdletBinding(DefaultParameterSetName='ByName')]\nparam($Name, $Id)", "")));
// Test with multiple attributes
let code4 = "[CmdletBinding()]\n[OutputType([string])]\nparam($Value)";
let result4 = extract_powershell_param_block_with_attributes(code4, true);
assert_eq!(
result4,
Some((
"[CmdletBinding()]\n[OutputType([string])]\nparam($Value)",
""
))
);
assert_eq!(result4, Some(("[CmdletBinding()]\n[OutputType([string])]\nparam($Value)", "")));
// Test with comment before attributes
let code5 = "# My function\n[CmdletBinding()]\nparam($Name)";
let result5 = extract_powershell_param_block_with_attributes(code5, true);
assert_eq!(
result5,
Some(("# My function\n[CmdletBinding()]\nparam($Name)", ""))
);
assert_eq!(result5, Some(("# My function\n[CmdletBinding()]\nparam($Name)", "")));
// Test with include_attributes = false (should only get param block, not attributes)
let code6 = "[CmdletBinding()]\nparam($Name)";
@@ -1327,10 +1224,7 @@ param(
// Test with code after param
let code7 = "[CmdletBinding()]\nparam($Name)\nWrite-Host 'Hello'";
let result7 = extract_powershell_param_block_with_attributes(code7, true);
assert_eq!(
result7,
Some(("[CmdletBinding()]\nparam($Name)", "\nWrite-Host 'Hello'"))
);
assert_eq!(result7, Some(("[CmdletBinding()]\nparam($Name)", "\nWrite-Host 'Hello'")));
// Test with code after param (without attributes)
let code8 = "[CmdletBinding()]\nparam($Name)\nWrite-Host 'Hello'";
@@ -1498,85 +1392,10 @@ param(
}
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
has_preprocessor: None
}
);
Ok(())
}
#[test]
fn test_detect_cmdlet_binding() {
// Basic CmdletBinding
let (has_cb, has_ssp) = detect_cmdlet_binding("[CmdletBinding()]\nparam($Name)");
assert!(has_cb);
assert!(!has_ssp);
// CmdletBinding with SupportsShouldProcess
let (has_cb, has_ssp) =
detect_cmdlet_binding("[CmdletBinding(SupportsShouldProcess=$true)]\nparam($Path)");
assert!(has_cb);
assert!(has_ssp);
// CmdletBinding with SupportsShouldProcess=false
let (has_cb, has_ssp) =
detect_cmdlet_binding("[CmdletBinding(SupportsShouldProcess=$false)]\nparam($Path)");
assert!(has_cb);
assert!(!has_ssp);
// No CmdletBinding
let (has_cb, has_ssp) = detect_cmdlet_binding("param($Name)");
assert!(!has_cb);
assert!(!has_ssp);
// Case insensitive
let (has_cb, has_ssp) =
detect_cmdlet_binding("[cmdletbinding(supportsshouldprocess=$true)]\nparam($X)");
assert!(has_cb);
assert!(has_ssp);
// Commented out CmdletBinding should NOT be detected
let (has_cb, has_ssp) =
detect_cmdlet_binding("# [CmdletBinding(SupportsShouldProcess=$true)]\nparam($Path)");
assert!(!has_cb);
assert!(!has_ssp);
}
#[test]
fn test_powershell_common_param_filtering() -> anyhow::Result<()> {
// Common parameters declared in param() should be filtered out
let code = r#"[CmdletBinding()]
param(
[string]$Name,
[switch]$Verbose,
[string]$ErrorAction,
[int]$Age
)"#;
let sig = parse_powershell_sig(code)?;
assert_eq!(sig.args.len(), 2);
assert_eq!(sig.args[0].name, "Name");
assert_eq!(sig.args[1].name, "Age");
assert_eq!(sig.has_cmd_binding, Some(true));
assert_eq!(sig.supports_should_process, None);
Ok(())
}
#[test]
fn test_powershell_sig_cmdlet_binding_metadata() -> anyhow::Result<()> {
// Script without CmdletBinding
let code = "param([string]$Name)";
let sig = parse_powershell_sig(code)?;
assert_eq!(sig.has_cmd_binding, None);
assert_eq!(sig.supports_should_process, None);
// Script with CmdletBinding + SupportsShouldProcess
let code = "[CmdletBinding(SupportsShouldProcess=$true)]\nparam([string]$Path)";
let sig = parse_powershell_sig(code)?;
assert_eq!(sig.has_cmd_binding, Some(true));
assert_eq!(sig.supports_should_process, Some(true));
assert_eq!(sig.args.len(), 1);
assert_eq!(sig.args[0].name, "Path");
Ok(())
}
}

View File

@@ -89,7 +89,6 @@ pub fn parse_csharp_sig_meta(code: &str) -> anyhow::Result<CsharpMainSigMeta> {
args,
has_preprocessor: None,
auto_kind,
..Default::default()
};
Ok(CsharpMainSigMeta { is_async, returns_void, class_name, main_sig, is_public })

View File

@@ -43,7 +43,6 @@ pub fn parse_go_sig(code: &str) -> anyhow::Result<MainArgSignature> {
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
})
} else {
Ok(MainArgSignature {
@@ -52,7 +51,6 @@ pub fn parse_go_sig(code: &str) -> anyhow::Result<MainArgSignature> {
args: vec![],
auto_kind: Some("lib".to_string()),
has_preprocessor: None,
..Default::default()
})
}
}
@@ -246,8 +244,7 @@ func main(x int, y string, z bool, l []string, o struct { Name string `json:"nam
},
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
has_preprocessor: None
}
);

View File

@@ -21,7 +21,6 @@ pub fn parse_graphql_sig(code: &str) -> anyhow::Result<MainArgSignature> {
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
})
} else {
Err(anyhow!("Error parsing sql".to_string()))
@@ -127,8 +126,7 @@ query($i: Int, $arr: [String]!, $wahoo: String = "wahoo") {
}
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
has_preprocessor: None
}
);

View File

@@ -81,7 +81,6 @@ pub fn parse_java_sig_meta(code: &str) -> anyhow::Result<JavaMainSigMeta> {
args,
has_preprocessor: None,
auto_kind,
..Default::default()
};
Ok(JavaMainSigMeta { returns_void, class_name, main_sig, is_public })

View File

@@ -56,7 +56,6 @@ mod test {
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
},
sig
);
@@ -84,7 +83,6 @@ mod test {
},],
auto_kind: None,
has_preprocessor: None,
..Default::default()
},
sig
);
@@ -122,7 +120,6 @@ mod test {
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
},
sig
);
@@ -235,7 +232,6 @@ mod test {
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
},
sig
);
@@ -283,7 +279,6 @@ mod test {
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
},
sig
);
@@ -348,7 +343,6 @@ mod test {
// },],
// auto_kind: None,
// has_preprocessor: None,
// ..Default::default()
// },
// sig
// );
@@ -379,7 +373,6 @@ mod test {
},],
auto_kind: None,
has_preprocessor: None,
..Default::default()
},
sig
);
@@ -427,7 +420,6 @@ mod test {
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
},
sig
);
@@ -456,7 +448,6 @@ mod test {
},],
auto_kind: None,
has_preprocessor: None,
..Default::default()
},
sig
);
@@ -489,7 +480,6 @@ mod test {
// },],
// auto_kind: None,
// has_preprocessor: None,
// ..Default::default()
// },
// sig
// );
@@ -552,7 +542,6 @@ mod test {
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
},
sig
);
@@ -646,7 +635,6 @@ mod test {
// ],
// auto_kind: None,
// has_preprocessor: None,
// ..Default::default()
// },
// sig
// );

View File

@@ -101,7 +101,6 @@ pub fn parse_php_signature(
args,
auto_kind: None,
has_preprocessor,
..Default::default()
})
} else {
Ok(MainArgSignature {
@@ -110,7 +109,6 @@ pub fn parse_php_signature(
args: vec![],
auto_kind: Some("lib".to_string()),
has_preprocessor,
..Default::default()
})
}
}
@@ -182,8 +180,7 @@ function main(string $input1 = \"hey\", bool $input2 = false, int $input3 = 3, f
}
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
has_preprocessor: None
}
);

View File

@@ -366,7 +366,6 @@ pub fn parse_python_signature(
Some("lib".to_string())
},
has_preprocessor: Some(has_preprocessor),
..Default::default()
});
}
@@ -478,7 +477,6 @@ pub fn parse_python_signature(
.collect(),
auto_kind: None,
has_preprocessor: Some(has_preprocessor),
..Default::default()
})
} else {
Ok(MainArgSignature {
@@ -491,7 +489,6 @@ pub fn parse_python_signature(
None
},
has_preprocessor: Some(has_preprocessor),
..Default::default()
})
}
}
@@ -758,8 +755,7 @@ def main(test1: str, name: datetime.datetime = datetime.now(), byte: bytes = byt
},
],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
has_preprocessor: Some(false)
}
);
@@ -824,8 +820,7 @@ def main(test1: str,
}
],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
has_preprocessor: Some(false)
}
);
@@ -885,8 +880,7 @@ def main(test1: str,
}
],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
has_preprocessor: Some(false)
}
);
@@ -930,8 +924,7 @@ def main(test1: Literal["foo", "bar"], test2: List[Literal["foo", "bar"]]): retu
}
],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
has_preprocessor: Some(false)
}
);
@@ -962,8 +955,7 @@ def main(test1: DynSelect_foo): return
oidx: None
}],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
has_preprocessor: Some(false)
}
);
@@ -987,8 +979,7 @@ def hello(): return
star_kwargs: false,
args: vec![],
auto_kind: Some("lib".to_string()),
has_preprocessor: Some(false),
..Default::default()
has_preprocessor: Some(false)
}
);
@@ -1016,8 +1007,7 @@ def main(): return
star_kwargs: false,
args: vec![],
auto_kind: None,
has_preprocessor: Some(true),
..Default::default()
has_preprocessor: Some(true)
}
);
@@ -1082,8 +1072,7 @@ def main(a: list, e: List[int], b: list = [1,2,3,4], c = [1,2,3,4], d = ["a", "b
}
],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
has_preprocessor: Some(false)
}
);
@@ -1132,8 +1121,7 @@ def main(a: str, b: Optional[str], c: str | None): return
},
],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
has_preprocessor: Some(false)
}
);

View File

@@ -30,7 +30,6 @@ pub fn parse_r_sig_meta(code: &str) -> anyhow::Result<MainArgSignature> {
args: args.unwrap_or_default(),
has_preprocessor: None,
auto_kind: None,
..Default::default()
};
Ok(main_sig)

View File

@@ -41,7 +41,6 @@ pub fn parse_ruby_sig_meta(code: &str) -> anyhow::Result<MainArgSignature> {
args: args.unwrap_or_default(),
has_preprocessor: None,
auto_kind,
..Default::default()
};
Ok(main_sig)

View File

@@ -30,7 +30,6 @@ pub fn parse_rust_signature(code: &str) -> anyhow::Result<MainArgSignature> {
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
})
} else {
Ok(MainArgSignature {
@@ -39,7 +38,6 @@ pub fn parse_rust_signature(code: &str) -> anyhow::Result<MainArgSignature> {
args: vec![],
auto_kind: Some("lib".to_string()),
has_preprocessor: None,
..Default::default()
})
}
}

View File

@@ -30,7 +30,6 @@ pub fn parse_mysql_sig(code: &str) -> anyhow::Result<MainArgSignature> {
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
})
} else {
Err(anyhow!("Error parsing sql".to_string()))
@@ -47,7 +46,6 @@ pub fn parse_oracledb_sig(code: &str) -> anyhow::Result<MainArgSignature> {
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
})
} else {
Err(anyhow!("Error parsing sql".to_string()))
@@ -69,7 +67,6 @@ pub fn parse_pgsql_sig_with_typed_schema(code: &str) -> anyhow::Result<(MainArgS
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
},
typed_schema,
))
@@ -88,7 +85,6 @@ pub fn parse_bigquery_sig(code: &str) -> anyhow::Result<MainArgSignature> {
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
})
} else {
Err(anyhow!("Error parsing sql".to_string()))
@@ -104,7 +100,6 @@ pub fn parse_duckdb_sig(code: &str) -> anyhow::Result<MainArgSignature> {
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
})
} else {
Err(anyhow!("Error parsing sql".to_string()))
@@ -121,7 +116,6 @@ pub fn parse_snowflake_sig(code: &str) -> anyhow::Result<MainArgSignature> {
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
})
} else {
Err(anyhow!("Error parsing sql".to_string()))
@@ -138,7 +132,6 @@ pub fn parse_mssql_sig(code: &str) -> anyhow::Result<MainArgSignature> {
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
})
} else {
Err(anyhow!("Error parsing sql".to_string()))
@@ -951,8 +944,7 @@ SELECT * FROM table WHERE token=$1::TEXT AND image=$2::BIGINT
},
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
has_preprocessor: None
}
);
@@ -1001,8 +993,7 @@ SELECT $2::TEXT;
},
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
has_preprocessor: None
}
);
@@ -1129,8 +1120,7 @@ SELECT ?, ?;
},
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
has_preprocessor: None
}
);
@@ -1178,8 +1168,7 @@ SELECT :param2;
},
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
has_preprocessor: None
}
);
@@ -1219,8 +1208,7 @@ SELECT @token;
},
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
has_preprocessor: None
}
);
@@ -1268,8 +1256,7 @@ SELECT ?;
}
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
has_preprocessor: None
}
);
@@ -1317,8 +1304,7 @@ SELECT @P2;
},
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
has_preprocessor: None
}
);
@@ -1367,8 +1353,7 @@ SELECT * FROM table_name WHERE thing = :name4;
},
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
has_preprocessor: None
}
);
@@ -1406,8 +1391,7 @@ SELECT * FROM users WHERE id = $1 AND email = $2::text;
},
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
has_preprocessor: None
}
);
@@ -1445,8 +1429,7 @@ SELECT * FROM users LIMIT $1 OFFSET $2;
},
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
has_preprocessor: None
}
);
@@ -1496,8 +1479,7 @@ WHERE id = $1
},
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
has_preprocessor: None
}
);
@@ -1524,8 +1506,7 @@ SELECT * FROM users WHERE id = ANY($1);
oidx: Some(1),
},],
auto_kind: None,
has_preprocessor: None,
..Default::default()
has_preprocessor: None
}
);
@@ -1554,8 +1535,7 @@ SELECT $1::integer;
oidx: Some(1),
},],
auto_kind: None,
has_preprocessor: None,
..Default::default()
has_preprocessor: None
}
);
@@ -1587,8 +1567,7 @@ SELECT x
oidx: None,
},],
auto_kind: None,
has_preprocessor: None,
..Default::default()
has_preprocessor: None
}
);

View File

@@ -462,7 +462,6 @@ pub fn parse_deno_signature(
},
auto_kind,
has_preprocessor: Some(has_preprocessor),
..Default::default()
};
Ok(r)
}

View File

@@ -47,7 +47,6 @@ mod tests {
args: vec![],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -106,7 +105,6 @@ mod tests {
],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -156,7 +154,6 @@ mod tests {
],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -206,7 +203,6 @@ mod tests {
],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -238,7 +234,6 @@ mod tests {
},],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -270,7 +265,6 @@ mod tests {
},],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -311,7 +305,6 @@ mod tests {
}],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -350,7 +343,6 @@ mod tests {
}],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -409,7 +401,6 @@ mod tests {
}],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -468,7 +459,6 @@ mod tests {
],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -518,7 +508,6 @@ mod tests {
],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -568,7 +557,6 @@ mod tests {
args: vec![],
auto_kind: Some("lib".to_string()),
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -596,7 +584,6 @@ mod tests {
}],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -626,7 +613,6 @@ mod tests {
}],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -656,7 +642,6 @@ mod tests {
}],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -706,7 +691,6 @@ mod tests {
],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
}
);
}
@@ -747,7 +731,6 @@ mod tests {
}],
auto_kind: None,
has_preprocessor: Some(true),
..Default::default()
}
);
}
@@ -778,7 +761,6 @@ mod tests {
}],
auto_kind: None,
has_preprocessor: Some(true),
..Default::default()
}
);
}

View File

@@ -141,8 +141,7 @@ export function main(test1?: string, test2: string = \"burkina\",
}
],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
has_preprocessor: Some(false)
}
);
@@ -221,8 +220,7 @@ export function main(test2 = \"burkina\",
}
],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
has_preprocessor: Some(false)
}
);
@@ -273,8 +271,7 @@ export function main(foo: FooBar, {a, b}: FooBar, {c, d}: FooBar = {a: \"foo\",
}
],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
has_preprocessor: Some(false)
}
);
@@ -306,8 +303,7 @@ export function main(foo: (\"foo\" | \"bar\")[]) {
oidx: None
}],
auto_kind: None,
has_preprocessor: Some(false),
..Default::default()
has_preprocessor: Some(false)
}
);
@@ -451,8 +447,7 @@ Write-Output 'Testing...'
}
],
auto_kind: None,
has_preprocessor: None,
..Default::default()
has_preprocessor: None
}
);

View File

@@ -27,7 +27,6 @@ pub fn parse_ansible_sig(inner_content: &str) -> anyhow::Result<MainArgSignature
args: vec![],
auto_kind: None,
has_preprocessor: None,
..Default::default()
});
}
@@ -95,7 +94,6 @@ pub fn parse_ansible_sig(inner_content: &str) -> anyhow::Result<MainArgSignature
args,
auto_kind: None,
has_preprocessor: None,
..Default::default()
})
}

View File

@@ -38,10 +38,6 @@ pub struct MainArgSignature {
pub args: Vec<Arg>,
pub auto_kind: Option<String>,
pub has_preprocessor: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub has_cmd_binding: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub supports_should_process: Option<bool>,
}
#[derive(Serialize, Clone, Debug, PartialEq)]

View File

@@ -41,69 +41,50 @@ pub async fn connect_db(
};
let pool = connect(database_url.clone(), max_connections, worker_mode).await?;
#[cfg(all(feature = "enterprise", feature = "private"))]
{
let needs_token_refresh = matches!(
database_url,
DatabaseUrl::IamRds(_) | DatabaseUrl::EntraId(_)
);
let label = match &database_url {
DatabaseUrl::IamRds(_) => "IAM RDS",
DatabaseUrl::EntraId(_) => "Entra ID",
DatabaseUrl::Static(_) => "",
};
if needs_token_refresh {
let pool2 = pool.clone();
let database_url2 = database_url.clone();
tokio::spawn(async move {
loop {
tokio::select! {
_ = killpill_rx.recv() => {
break;
}
_ = tokio::time::sleep(std::time::Duration::from_secs(10)) => {
if !database_url2.needs_refresh().await {
continue;
}
let new_url = tokio::time::timeout(
std::time::Duration::from_secs(10),
get_database_url(),
)
.await;
let pool2 = pool.clone();
#[cfg(all(feature = "enterprise", feature = "private"))]
if let DatabaseUrl::IamRds(database_url) = database_url {
tokio::spawn(async move {
loop {
tokio::select! {
_ = killpill_rx.recv() => {
break;
}
_ = tokio::time::sleep(std::time::Duration::from_secs(10)) => {
let needs_refresh = {
let read_guard = database_url.read().await;
read_guard.needs_refresh()
};
if needs_refresh {
let new_url = tokio::time::timeout(std::time::Duration::from_secs(10), get_database_url()).await;
match new_url {
Ok(Ok(new_url)) => {
match new_url.connect_options().await {
Ok(connect_options) => {
pool2.set_connect_options(connect_options);
tracing::info!("Refreshed {label} URL successfully");
tracing::info!("Refreshed IAM RDS URL successfully");
}
Err(e) => {
tracing::error!(
"Error getting {label} connect options, retrying in 10s: {e}"
);
tracing::error!("Error getting IAM RDS connect options, retrying in 10s: {}", e);
continue;
}
}
}
Ok(Err(e)) => {
tracing::error!(
"Error refreshing {label} URL, trying again in 10s: {e}"
);
tracing::error!("Error refreshing IAM RDS URL, trying again in 10s: {}", e);
continue;
}
Err(e) => {
tracing::error!(
"Timeout after 10s refreshing {label} URL, trying again in 10s: {e}"
);
tracing::error!("Timeout after 10s refreshing IAM RDS URL, trying again in 10 seconds: {}", e);
continue;
}
}
}
}
}
});
}
}
});
}
Ok(pool)

View File

@@ -1597,12 +1597,6 @@ async fn process_notify_event(
tracing::debug!("config changed but did not target this server/worker");
}
}
"restart_worker_group" => {
if worker_mode && payload == *WORKER_GROUP {
tracing::info!("Restart requested for worker group '{payload}'");
spawn_graceful_killpill(tx, db, 10, "worker group restart requested").await;
}
}
"notify_webhook_change" => {
tracing::info!(
"Webhook change detected, invalidating webhook cache: {}",

View File

@@ -38,7 +38,7 @@ account: workspace_id(char), id(int), expires_at(ts), refresh_token(char), clien
agent_token_blacklist: token(char), expires_at(ts), blacklisted_at(ts), blacklisted_by(char)
ai_agent_memory: workspace_id(char), conversation_id(uuid), step_id(char), messages(jsonb), created_at(ts), updated_at(ts)
alerts: id(int), alert_type(char), message(text), created_at(ts), acknowledged(bool), workspace_id(text), acknowledged_workspace(bool), resource(text)
app: id(bigint), workspace_id(char), path(char), summary(char), policy(jsonb), versions(bigint[]), extra_perms(jsonb), draft_only(bool), custom_path(text), labels(text[])
app: id(bigint), workspace_id(char), path(char), summary(char), policy(jsonb), versions(bigint[]), extra_perms(jsonb), draft_only(bool), custom_path(text)
FK: (workspace_id) -> workspace(id)
app_bundles: app_version_id(bigint), w_id(char), file_type(char), data(bytes)
app_script: id(bigint), app(bigint), hash(char(64)), lock(text), code(text), code_sha256(char(64))
@@ -72,9 +72,9 @@ deployment_metadata: workspace_id(char), path(char), script_hash(bigint), app_ve
draft: workspace_id(char), path(char), typ(draft_type), value(json), created_at(ts)
FK: (workspace_id) -> workspace(id)
email_to_igroup: email(char), igroup(char)
email_trigger: path(char), local_part(char), workspaced_local_part(bool), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode), labels(text[])
email_trigger: path(char), local_part(char), workspaced_local_part(bool), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode)
favorite: usr(char), workspace_id(char), path(char), favorite_kind(favorite_kind)
flow: workspace_id(char), path(char), summary(text), description(text), value(jsonb), edited_by(char), edited_at(ts), archived(bool), schema(json), extra_perms(jsonb), dependency_job(uuid), draft_only(bool), tag(char), ws_error_handler_muted(bool), dedicated_worker(bool), timeout(int), visible_to_runner_only(bool), concurrency_key(char), versions(bigint[]), on_behalf_of_email(text), lock_error_logs(text), labels(text[])
flow: workspace_id(char), path(char), summary(text), description(text), value(jsonb), edited_by(char), edited_at(ts), archived(bool), schema(json), extra_perms(jsonb), dependency_job(uuid), draft_only(bool), tag(char), ws_error_handler_muted(bool), dedicated_worker(bool), timeout(int), visible_to_runner_only(bool), concurrency_key(char), versions(bigint[]), on_behalf_of_email(text), lock_error_logs(text)
FK: (workspace_id) -> workspace(id)
flow_conversation: id(uuid), workspace_id(char), flow_path(char), title(char), created_at(ts), updated_at(ts), created_by(char)
FK: (workspace_id) -> workspace(id)
@@ -91,14 +91,14 @@ folder: name(char), workspace_id(char), display_name(char), owners(char), extra_
FK: (workspace_id) -> workspace(id)
folder_permission_history: id(bigint), workspace_id(char), folder_name(char), changed_by(char), changed_at(ts), change_type(char), affected(char)
FK: (workspace_id, folder_name) -> folder(workspace_id, name)
gcp_trigger: gcp_resource_path(char), topic_id(char), subscription_id(char), delivery_type(delivery_mode), delivery_config(jsonb), path(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), subscription_mode(gcp_subscription_mode), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), auto_acknowledge_msg(bool), ack_deadline(int), mode(trigger_mode), labels(text[])
gcp_trigger: gcp_resource_path(char), topic_id(char), subscription_id(char), delivery_type(delivery_mode), delivery_config(jsonb), path(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), subscription_mode(gcp_subscription_mode), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), auto_acknowledge_msg(bool), ack_deadline(int), mode(trigger_mode)
global_settings: name(char), value(jsonb), updated_at(ts)
group_: workspace_id(char), name(char), summary(text), extra_perms(jsonb)
FK: (workspace_id) -> workspace(id)
group_permission_history: id(bigint), workspace_id(char), group_name(char), changed_by(char), changed_at(ts), change_type(char), member_affected(char)
FK: (workspace_id, group_name) -> group_(workspace_id, name)
healthchecks: id(bigint), check_type(char), healthy(bool), created_at(ts)
http_trigger: path(char), route_path(char), route_path_key(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), authentication_method(authentication_method), http_method(http_method), static_asset_config(jsonb), is_static_website(bool), workspaced_route(bool), wrap_body(bool), raw_string(bool), authentication_resource_path(char), summary(char), description(text), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), request_type(request_type), mode(trigger_mode), labels(text[])
http_trigger: path(char), route_path(char), route_path_key(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), authentication_method(authentication_method), http_method(http_method), static_asset_config(jsonb), is_static_website(bool), workspaced_route(bool), wrap_body(bool), raw_string(bool), authentication_resource_path(char), summary(char), description(text), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), request_type(request_type), mode(trigger_mode)
input: id(uuid), workspace_id(char), runnable_id(char), runnable_type(runnable_type), name(text), args(jsonb), created_at(ts), created_by(char), is_public(bool)
FK: (workspace_id) -> workspace(id)
instance_group: name(char), summary(char), id(char), scim_display_name(char), external_id(char)
@@ -111,7 +111,7 @@ job_stats: workspace_id(char), job_id(uuid), metric_id(char), metric_name(char),
FK: (workspace_id) -> workspace(id)
kafka_pending_commits: id(bigint), workspace_id(char), kafka_trigger_path(char), topic(char), partition(int), offset(bigint), created_at(ts)
FK: (workspace_id, kafka_trigger_path) -> kafka_trigger(workspace_id, path)
kafka_trigger: path(char), kafka_resource_path(char), topics(char), group_id(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode), filters(jsonb[]), auto_commit(bool), labels(text[])
kafka_trigger: path(char), kafka_resource_path(char), topics(char), group_id(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode), filters(jsonb[]), auto_commit(bool)
log_file: hostname(char), log_ts(ts), ok_lines(bigint), err_lines(bigint), mode(log_mode), worker_group(char), file_path(char), json_fmt(bool)
magic_link: email(char), token(char), expiration(ts)
mcp_oauth_client: mcp_server_url(text), client_id(text), client_secret(text), client_secret_expires_at(ts), token_endpoint(text), created_at(ts)
@@ -121,10 +121,10 @@ mcp_oauth_server_client: client_id(char), client_name(char), redirect_uris(text[
mcp_oauth_server_code: code(char), client_id(char), user_email(char), workspace_id(char), scopes(text[]), redirect_uri(text), code_challenge(char), code_challenge_method(char), created_at(ts), expires_at(ts)
FK: (client_id) -> mcp_oauth_server_client(client_id)
metrics: id(char), value(jsonb), created_at(ts)
mqtt_trigger: mqtt_resource_path(char), subscribe_topics(jsonb[]), client_version(mqtt_client_version), v5_config(jsonb), v3_config(jsonb), client_id(char), path(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode), labels(text[])
mqtt_trigger: mqtt_resource_path(char), subscribe_topics(jsonb[]), client_version(mqtt_client_version), v5_config(jsonb), v3_config(jsonb), client_id(char), path(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode)
native_trigger: external_id(char), workspace_id(char), service_name(native_trigger_service), script_path(char), is_flow(bool), webhook_token_hash(char), service_config(jsonb), error(text), created_at(ts), updated_at(ts)
FK: (workspace_id) -> workspace(id)
nats_trigger: path(char), nats_resource_path(char), subjects(char), stream_name(char), consumer_name(char), use_jetstream(bool), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode), labels(text[])
nats_trigger: path(char), nats_resource_path(char), subjects(char), stream_name(char), consumer_name(char), use_jetstream(bool), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode)
FK: (workspace_id) -> workspace(id)
notify_event: id(bigint), channel(text), payload(text), created_at(ts)
otel_traces: trace_id(bytes), span_id(bytes), trace_state(text), parent_span_id(bytes), flags(int), name(text), kind(int), start_time_unix_nano(bigint), end_time_unix_nano(bigint), attributes(jsonb), dropped_attributes_count(int), events(jsonb), dropped_events_count(int), links(jsonb), dropped_links_count(int), status(jsonb)
@@ -133,23 +133,23 @@ parallel_monitor_lock: parent_flow_id(uuid), job_id(uuid), last_ping(ts)
password: email(char), password_hash(char), login_type(char), super_admin(bool), verified(bool), name(char), company(char), first_time_user(bool), username(char), devops(bool)
pending_user: email(char), created_at(ts), username(char)
pip_resolution_cache: hash(char), expiration(ts), lockfile(text)
postgres_trigger: path(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), postgres_resource_path(char), error(text), server_id(char), last_server_ping(ts), replication_slot_name(char), publication_name(char), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode), labels(text[])
postgres_trigger: path(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), postgres_resource_path(char), error(text), server_id(char), last_server_ping(ts), replication_slot_name(char), publication_name(char), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode)
FK: (workspace_id) -> workspace(id)
raw_app: path(char), version(int), workspace_id(char), summary(char), edited_at(ts), data(text), extra_perms(jsonb), labels(text[])
raw_app: path(char), version(int), workspace_id(char), summary(char), edited_at(ts), data(text), extra_perms(jsonb)
FK: (workspace_id) -> workspace(id)
resource: workspace_id(char), path(char), value(jsonb), description(text), resource_type(char), extra_perms(jsonb), edited_at(ts), created_by(char), labels(text[])
resource: workspace_id(char), path(char), value(jsonb), description(text), resource_type(char), extra_perms(jsonb), edited_at(ts), created_by(char)
FK: (workspace_id) -> workspace(id)
resource_type: workspace_id(char), name(char), schema(jsonb), description(text), edited_at(ts), created_by(char), format_extension(char), is_fileset(bool)
FK: (workspace_id) -> workspace(id)
resume_job: id(uuid), job(uuid), flow(uuid), created_at(ts), value(jsonb), approver(char), resume_id(int), approved(bool)
FK: (flow) -> v2_job_queue(id)
runnable_settings: hash(bigint), debouncing_settings(bigint), concurrency_settings(bigint)
schedule: workspace_id(char), path(char), edited_by(char), edited_at(ts), schedule(char), enabled(bool), script_path(char), args(jsonb), extra_perms(jsonb), is_flow(bool), email(char), error(text), timezone(char), on_failure(char), on_recovery(char), on_failure_times(int), on_failure_exact(bool), on_failure_extra_args(jsonb), on_recovery_times(int), on_recovery_extra_args(jsonb), ws_error_handler_muted(bool), retry(jsonb), summary(char), no_flow_overlap(bool), tag(char), paused_until(ts), on_success(char), on_success_extra_args(jsonb), cron_version(text), description(text), dynamic_skip(char), labels(text[])
schedule: workspace_id(char), path(char), edited_by(char), edited_at(ts), schedule(char), enabled(bool), script_path(char), args(jsonb), extra_perms(jsonb), is_flow(bool), email(char), error(text), timezone(char), on_failure(char), on_recovery(char), on_failure_times(int), on_failure_exact(bool), on_failure_extra_args(jsonb), on_recovery_times(int), on_recovery_extra_args(jsonb), ws_error_handler_muted(bool), retry(jsonb), summary(char), no_flow_overlap(bool), tag(char), paused_until(ts), on_success(char), on_success_extra_args(jsonb), cron_version(text), description(text), dynamic_skip(char)
FK: (workspace_id) -> workspace(id)
script: workspace_id(char), hash(bigint), path(char), parent_hashes(bigint[]), summary(text), description(text), content(text), created_by(char), created_at(ts), archived(bool), schema(json), deleted(bool), is_template(bool), extra_perms(jsonb), lock(text), lock_error_logs(text), language(script_lang), kind(script_kind), tag(char), draft_only(bool), envs(char), concurrent_limit(int), concurrency_time_window_s(int), cache_ttl(int), dedicated_worker(bool), ws_error_handler_muted(bool), priority(smallint), timeout(int), delete_after_use(bool), restart_unless_cancelled(bool), concurrency_key(char), visible_to_runner_only(bool), auto_kind(varchar), codebase(char), has_preprocessor(bool), on_behalf_of_email(text), schema_validation(bool), assets(jsonb), debounce_key(char), debounce_delay_s(int), cache_ignore_s3_path(bool), runnable_settings_handle(bigint), labels(text[])
script: workspace_id(char), hash(bigint), path(char), parent_hashes(bigint[]), summary(text), description(text), content(text), created_by(char), created_at(ts), archived(bool), schema(json), deleted(bool), is_template(bool), extra_perms(jsonb), lock(text), lock_error_logs(text), language(script_lang), kind(script_kind), tag(char), draft_only(bool), envs(char), concurrent_limit(int), concurrency_time_window_s(int), cache_ttl(int), dedicated_worker(bool), ws_error_handler_muted(bool), priority(smallint), timeout(int), delete_after_use(bool), restart_unless_cancelled(bool), concurrency_key(char), visible_to_runner_only(bool), auto_kind(varchar), codebase(char), has_preprocessor(bool), on_behalf_of_email(text), schema_validation(bool), assets(jsonb), debounce_key(char), debounce_delay_s(int), cache_ignore_s3_path(bool), runnable_settings_handle(bigint)
FK: (workspace_id) -> workspace(id)
skip_workspace_diff_tally: workspace_id(char), added_at(ts)
sqs_trigger: path(char), queue_url(char), aws_resource_path(char), message_attributes(text[]), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), error(text), server_id(char), last_server_ping(ts), aws_auth_resource_type(aws_auth_resource_type), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode), labels(text[])
sqs_trigger: path(char), queue_url(char), aws_resource_path(char), message_attributes(text[]), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), error(text), server_id(char), last_server_ping(ts), aws_auth_resource_type(aws_auth_resource_type), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), mode(trigger_mode)
FK: (workspace_id) -> workspace(id)
trashbin: id(bigint), workspace_id(char), item_kind(char), item_path(char), item_data(jsonb), deleted_by(char), deleted_at(ts), expires_at(ts)
FK: (workspace_id) -> workspace(id)
@@ -173,9 +173,9 @@ v2_job_runtime: id(uuid), ping(ts), memory_peak(int)
FK: (id) -> v2_job_queue(id)
v2_job_status: id(uuid), flow_status(jsonb), flow_leaf_jobs(jsonb), workflow_as_code_status(jsonb)
FK: (id) -> v2_job_queue(id)
variable: workspace_id(char), path(char), value(char), is_secret(bool), description(char), extra_perms(jsonb), account(int), is_oauth(bool), expires_at(ts), labels(text[])
variable: workspace_id(char), path(char), value(char), is_secret(bool), description(char), extra_perms(jsonb), account(int), is_oauth(bool), expires_at(ts)
FK: (workspace_id) -> workspace(id)
websocket_trigger: path(char), url(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), filters(jsonb[]), initial_messages(jsonb[]), url_runnable_args(jsonb), can_return_message(bool), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), can_return_error_result(bool), mode(trigger_mode), labels(text[])
websocket_trigger: path(char), url(char), script_path(char), is_flow(bool), workspace_id(char), edited_by(char), email(char), edited_at(ts), extra_perms(jsonb), server_id(char), last_server_ping(ts), error(text), filters(jsonb[]), initial_messages(jsonb[]), url_runnable_args(jsonb), can_return_message(bool), error_handler_path(char), error_handler_args(jsonb), retry(jsonb), can_return_error_result(bool), mode(trigger_mode)
windmill_migrations: name(text), created_at(ts)
worker_group_job_stats: hour(bigint), worker_group(text), script_lang(char), workspace_id(char), job_count(int), total_duration_ms(bigint)
FK: (workspace_id) -> workspace(id)

View File

@@ -429,59 +429,6 @@ export function main() {
Ok(())
}
#[sqlx::test(fixtures("base"))]
async fn test_bun_job_syntax_error_unclosed_bracket(db: Pool<Postgres>) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
let port = server.addr.port();
// Reproduces the "Unexpected end of file at main.ts:0" error reported
// when a TS file has a missing closing bracket — Bun's bundler gives no
// useful location info.
let content = r#"
export async function main() {
if (true) {
return "hello";
// missing closing bracket for the function
"#
.to_owned();
let job = JobPayload::Code(RawCode {
hash: None,
content,
path: None,
language: ScriptLang::Bun,
lock: None,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
modules: None,
});
let completed = run_job_in_new_worker_until_complete(&db, false, job, port).await;
assert!(!completed.success);
let result = completed
.result
.as_ref()
.and_then(|v| v.get("error"))
.and_then(|v| v.get("message"))
.and_then(|v| v.as_str())
.unwrap_or("");
assert!(
result.contains("Unexpected end of file"),
"should contain bun parser error, got: {result}"
);
assert!(
result.contains("syntax error"),
"should contain helpful hint about syntax errors, got: {result}"
);
Ok(())
}
// ============================================================================
// Annotation Mode Tests
// ============================================================================
@@ -1066,8 +1013,8 @@ mod dedicated_worker_protocol {
let mut results = Vec::new();
for job_args in jobs {
// Protocol: execd:<json_args> (single-script, no path needed)
writeln!(stdin, "execd:{}", job_args.to_string()).unwrap();
// Protocol: exec:<script_path>:<json_args>
writeln!(stdin, "exec:{}:{}", TEST_SCRIPT_PATH, job_args.to_string()).unwrap();
stdin.flush().unwrap();
let mut response = String::new();
@@ -1653,6 +1600,8 @@ mod dedicated_worker_protocol_deno {
use windmill_test_utils::{parse_dedicated_worker_line, DedicatedWorkerResult};
use windmill_worker::{generate_deno_dedicated_worker_wrapper, DENO_PATH};
const TEST_SCRIPT_PATH: &str = "f/test/script";
fn run_deno_worker_test(
script: &str,
jobs: Vec<serde_json::Value>,
@@ -1702,7 +1651,7 @@ mod dedicated_worker_protocol_deno {
let mut results = Vec::new();
for job_args in jobs {
writeln!(stdin, "execd:{}", job_args.to_string()).unwrap();
writeln!(stdin, "exec:{}:{}", TEST_SCRIPT_PATH, job_args.to_string()).unwrap();
stdin.flush().unwrap();
loop {
@@ -1823,13 +1772,7 @@ export function main(msg: string): never {
let mut results = Vec::new();
for (cmd, args) in &commands {
// Single-script Deno wrapper uses execd:/execd_preprocess: (no path)
let direct_cmd = if *cmd == "exec_preprocess" {
"execd_preprocess"
} else {
"execd"
};
writeln!(stdin, "{}:{}", direct_cmd, args).unwrap();
writeln!(stdin, "{}:{}:{}", cmd, TEST_SCRIPT_PATH, args).unwrap();
stdin.flush().unwrap();
let expected_lines = if *cmd == "exec_preprocess" { 2 } else { 1 };

File diff suppressed because it is too large Load Diff

View File

@@ -450,7 +450,6 @@ def main():
on_behalf_of_email: None,
preserve_on_behalf_of: None,
ws_error_handler_muted: None,
labels: None,
})
.send()
.await
@@ -512,7 +511,6 @@ def main():
deployment_message: None,
custom_path: None,
preserve_on_behalf_of: None,
labels: None,
})
.send()
.await

View File

@@ -162,7 +162,7 @@ export async function main(path: string, email: string, job_id: string, is_flow:
priority: None,
apply_preprocessor: false,
concurrency_settings: ConcurrencySettings::default(),
debouncing_settings: DebouncingSettings::default(), labels: None,
debouncing_settings: DebouncingSettings::default(),
})
.run_until_complete(&db, false, server.addr.port())
.await;
@@ -285,7 +285,7 @@ async fn test_error_handler_muted_on_script(db: Pool<Postgres>) -> anyhow::Resul
priority: None,
apply_preprocessor: false,
concurrency_settings: ConcurrencySettings::default(),
debouncing_settings: DebouncingSettings::default(), labels: None,
debouncing_settings: DebouncingSettings::default(),
})
.run_until_complete(&db, false, server.addr.port())
.await;
@@ -380,7 +380,7 @@ async fn test_error_handler_not_triggered_on_success(db: Pool<Postgres>) -> anyh
priority: None,
apply_preprocessor: false,
concurrency_settings: ConcurrencySettings::default(),
debouncing_settings: DebouncingSettings::default(), labels: None,
debouncing_settings: DebouncingSettings::default(),
})
.run_until_complete(&db, false, server.addr.port())
.await;

View File

@@ -1,599 +0,0 @@
-- Fixtures for dedicated worker E2E tests
-- A simple Bun script for testing dedicated Script steps in flows
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'export function main(x: number) { return x * 2; }',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/dedicated_double', 300001, 'bun', E'{}\n//bun.lock\n<empty>', true);
-- Flow with a single RawScript inline bun step (the "Script not found" bug case)
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_rawscript_flow',
'{3000000000000001}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 10; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000001,
'test-workspace',
'f/system/dedicated_rawscript_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 10; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
-- Flow with a Script step referencing the external dedicated_double script
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_script_flow',
'{3000000000000002}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'{"modules":[{"id":"a","value":{"type":"script","path":"f/system/dedicated_double","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}}}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000002,
'test-workspace',
'f/system/dedicated_script_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'{"modules":[{"id":"a","value":{"type":"script","path":"f/system/dedicated_double","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}}}}]}',
'system'
);
-- Flow with two inline RawScript steps (tests multi-step key uniqueness)
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_multi_step_flow',
'{3000000000000003}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 1; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}},{"id":"b","value":{"type":"rawscript","content":"export function main(x: number) { return x * 3; }","language":"bun","input_transforms":{"x":{"expr":"results.a","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000003,
'test-workspace',
'f/system/dedicated_multi_step_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 1; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}},{"id":"b","value":{"type":"rawscript","content":"export function main(x: number) { return x * 3; }","language":"bun","input_transforms":{"x":{"expr":"results.a","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
-- Two scripts sharing a workspace dependency for runner group testing.
-- Both reference the same external dep "f/system/dedicated_double" via extra_package_json annotation.
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'// extra_package_json: f/system/dedicated_double\nexport function main(x: number) { return x + 100; }',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/rg_script_a', 300010, 'bun', E'{}\n//bun.lock\n<empty>', true);
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'// extra_package_json: f/system/dedicated_double\nexport function main(x: number) { return x + 200; }',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/rg_script_b', 300011, 'bun', E'{}\n//bun.lock\n<empty>', true);
-- Flow with a Deno inline RawScript step
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_deno_flow',
'{3000000000000005}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 100; }","language":"deno","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}}}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000005,
'test-workspace',
'f/system/dedicated_deno_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 100; }","language":"deno","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}}}}]}',
'system'
);
-- Flow with a Python inline RawScript step
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_python_flow',
'{3000000000000006}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"def main(x: int):\\n return x + 100","language":"python3","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}}}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000006,
'test-workspace',
'f/system/dedicated_python_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"def main(x: int):\\n return x + 100","language":"python3","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}}}}]}',
'system'
);
-- Flow with a Bunnative (//native) inline RawScript step
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_bunnative_flow',
'{3000000000000007}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"//native\\nexport function main(x: number) { return x + 100; }","language":"bunnative","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000007,
'test-workspace',
'f/system/dedicated_bunnative_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"//native\\nexport function main(x: number) { return x + 100; }","language":"bunnative","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
-- Flow with a Bun + //nodejs annotation inline RawScript step
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_nodejs_flow',
'{3000000000000008}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"//nodejs\\nexport function main(x: number) { return x + 100; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000008,
'test-workspace',
'f/system/dedicated_nodejs_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"//nodejs\\nexport function main(x: number) { return x + 100; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
-- Flow with a squashed for-loop for testing flow runners.
-- The for-loop iterates over [1, 2, 3], each iteration runs a simple bun rawscript.
-- squash=true triggers spawn_flow_module_runners to create dedicated subprocesses.
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_flow_runners',
'{3000000000000004}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"forloopflow","iterator":{"type":"javascript","expr":"[1, 2, 3]"},"skip_failures":false,"parallel":false,"squash":true,"modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(iter: {value: number, index: number}) { return iter.value * 10; }","language":"bun","input_transforms":{"iter":{"expr":"flow_input.iter","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000004,
'test-workspace',
'f/system/dedicated_flow_runners',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"forloopflow","iterator":{"type":"javascript","expr":"[1, 2, 3]"},"skip_failures":false,"parallel":false,"squash":true,"modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(iter: {value: number, index: number}) { return iter.value * 10; }","language":"bun","input_transforms":{"iter":{"expr":"flow_input.iter","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}}]}',
'system'
);
-- Two flows with conflicting step IDs (both have module "a") but different RawScript content.
-- Tests that runnable_path-based lookup correctly disambiguates them.
-- Flow A: x + 1000
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/conflict_flow_a',
'{3000000000000009}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 1000; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000009,
'test-workspace',
'f/system/conflict_flow_a',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 1000; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
-- Flow B: x + 2000
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/conflict_flow_b',
'{3000000000000010}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 2000; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000010,
'test-workspace',
'f/system/conflict_flow_b',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 2000; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}',
'system'
);
-- A dedicated worker script with a preprocessor function.
-- preprocessor doubles x, main adds 100.
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'export function preprocessor(x: number) { return { x: x * 2 }; }\nexport function main(x: number) { return x + 100; }',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/preprocess_script', 300030, 'bun', E'{}\n//bun.lock\n<empty>', true);
-- Second workspace for cross-workspace isolation testing.
INSERT INTO workspace(id, name, owner) VALUES ('test-workspace-2', 'test-workspace-2', 'test-user');
INSERT INTO usr(workspace_id, email, username, is_admin, role) VALUES
('test-workspace-2', 'test@windmill.dev', 'test-user', true, 'Admin');
INSERT INTO workspace_key(workspace_id, kind, key) VALUES
('test-workspace-2', 'cloud', 'test-key-2');
INSERT INTO workspace_settings (workspace_id) VALUES ('test-workspace-2');
INSERT INTO group_ (workspace_id, name, summary, extra_perms) VALUES
('test-workspace-2', 'all', 'All users', '{}');
-- Same path as dedicated_double but in workspace 2, returns x * 3 instead of x * 2.
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace-2',
'system',
E'export function main(x: number) { return x * 3; }',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/dedicated_double', 300040, 'bun', E'{}\n//bun.lock\n<empty>', true);
-- ============================================================
-- Test: flow Script step + standalone conflict
-- Flow references dedicated_double (also configured as standalone).
-- Standalone worker should handle both its own jobs and the flow's Script step jobs.
-- ============================================================
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_conflict_standalone_flow',
'{3000000000000011}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'{"modules":[{"id":"a","value":{"type":"script","path":"f/system/dedicated_double","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}}}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000011,
'test-workspace',
'f/system/dedicated_conflict_standalone_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'{"modules":[{"id":"a","value":{"type":"script","path":"f/system/dedicated_double","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}}}}]}',
'system'
);
-- ============================================================
-- Test: non-dedicated step inside dedicated flow
-- Flow with bun step (x + 10) then bash step (echo result * 2).
-- The bun step runs on dedicated worker; bash falls back to normal execution.
-- ============================================================
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_mixed_lang_flow',
'{3000000000000012}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 10; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}},{"id":"b","value":{"type":"rawscript","content":"echo done","language":"bash","input_transforms":{"results_a":{"expr":"results.a","type":"javascript"}}}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000012,
'test-workspace',
'f/system/dedicated_mixed_lang_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"rawscript","content":"export function main(x: number) { return x + 10; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}},{"id":"b","value":{"type":"rawscript","content":"echo done","language":"bash","input_transforms":{"results_a":{"expr":"results.a","type":"javascript"}}}}]}',
'system'
);
-- ============================================================
-- Test: non-dedicated step inside flow runners (squashed loop)
-- Squashed for-loop with a bash step. Bash can't spawn a flow runner,
-- so each iteration falls back to normal execution.
-- ============================================================
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_flow_runners_bash',
'{3000000000000013}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"forloopflow","iterator":{"type":"javascript","expr":"[1, 2, 3]"},"skip_failures":false,"parallel":false,"squash":true,"modules":[{"id":"b","value":{"type":"rawscript","content":"echo done","language":"bash","input_transforms":{"iter_value":{"expr":"flow_input.iter.value","type":"javascript"}}}}]}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000013,
'test-workspace',
'f/system/dedicated_flow_runners_bash',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"forloopflow","iterator":{"type":"javascript","expr":"[1, 2, 3]"},"skip_failures":false,"parallel":false,"squash":true,"modules":[{"id":"b","value":{"type":"rawscript","content":"echo done","language":"bash","input_transforms":{"iter_value":{"expr":"flow_input.iter.value","type":"javascript"}}}}]}}]}',
'system'
);
-- ============================================================
-- Test: Python runner group
-- Two Python scripts sharing a workspace dependency annotation.
-- ============================================================
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'# extra_requirements: f/system/dedicated_double\ndef main(x: int):\n return x + 100',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/py_rg_script_a', 300050, 'python3', '', true);
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'# extra_requirements: f/system/dedicated_double\ndef main(x: int):\n return x + 200',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/py_rg_script_b', 300051, 'python3', '', true);
-- ============================================================
-- Test: preprocessor in runner group
-- Two bun scripts sharing a workspace dep, one has a preprocessor.
-- Tests exec_preprocess:{path}:{args} protocol in runner groups.
-- ============================================================
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'// extra_package_json: f/system/dedicated_double\nexport function preprocessor(x: number) { return { x: x * 2 }; }\nexport function main(x: number) { return x + 100; }',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/rg_preprocess_script', 300052, 'bun', E'{}\n//bun.lock\n<empty>', true);
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'// extra_package_json: f/system/dedicated_double\nexport function main(x: number) { return x + 300; }',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/rg_preprocess_other', 300053, 'bun', E'{}\n//bun.lock\n<empty>', true);
-- ============================================================
-- Test: flow with BranchOne
-- Flow with branchone: condition true → branch (x + 100), default → (x + 200).
-- Tests recursive module traversal for spawning dedicated workers.
-- ============================================================
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_branch_flow',
'{3000000000000014}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"branchone","branches":[{"expr":"flow_input.x > 10","modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(x: number) { return x + 100; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}],"default":[{"id":"c","value":{"type":"rawscript","content":"export function main(x: number) { return x + 200; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000014,
'test-workspace',
'f/system/dedicated_branch_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"branchone","branches":[{"expr":"flow_input.x > 10","modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(x: number) { return x + 100; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}],"default":[{"id":"c","value":{"type":"rawscript","content":"export function main(x: number) { return x + 200; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}}]}',
'system'
);
-- ============================================================
-- Test: Python standalone preprocessor
-- Python script with preprocessor function. Tests execd_preprocess: protocol.
-- ============================================================
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'def preprocessor(x: int):\n return {"x": x * 2}\n\ndef main(x: int):\n return x + 100',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/py_preprocess_script', 300054, 'python3', '', true);
-- ============================================================
-- Test: Deno standalone preprocessor
-- Deno script with preprocessor function. Tests execd_preprocess: protocol.
-- ============================================================
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'export function preprocessor(x: number) { return { x: x * 2 }; }\nexport function main(x: number) { return x + 100; }',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/deno_preprocess_script', 300055, 'deno', '', true);
-- ============================================================
-- Test: Python runner group preprocessor
-- Two Python scripts sharing a workspace dep, one has a preprocessor.
-- Tests exec_preprocess:{path}:{args} protocol for Python runner groups.
-- ============================================================
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'# extra_requirements: f/system/py_preprocess_script\ndef preprocessor(x: int):\n return {"x": x * 2}\n\ndef main(x: int):\n return x + 100',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/py_rg_preprocess_a', 300056, 'python3', '', true);
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'# extra_requirements: f/system/py_preprocess_script\ndef main(x: int):\n return x + 300',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/py_rg_preprocess_b', 300057, 'python3', '', true);
-- ============================================================
-- Test: Bunnative standalone preprocessor
-- Bunnative script with preprocessor function. Tests V8 isolate preprocessing.
-- ============================================================
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'//native\nexport function preprocessor(x: number) { return { x: x * 2 }; }\nexport function main(x: number) { return x + 100; }',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/bunnative_preprocess_script', 300058, 'bunnative', E'{}\n//bun.lock\n<empty>', true);
-- ============================================================
-- Test: Bun dedicated worker with relative imports
-- Helper script at f/system/dedicated_helper (returns x * 10).
-- Dedicated script imports from it using a relative path.
-- ============================================================
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock) VALUES (
'test-workspace',
'system',
E'export function helper(x: number) { return x * 10; }',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
'', '',
'f/system/dedicated_helper', 300060, 'bun', E'{}\n//bun.lock\n<empty>');
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'import { helper } from "./dedicated_helper.ts";\n\nexport function main(x: number) { return helper(x) + 1; }',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/dedicated_with_import', 300061, 'bun', E'{}\n//bun.lock\n<empty>', true);
-- ============================================================
-- Test: Python dedicated worker with relative imports
-- Helper script at f/system/py_dedicated_helper (returns x * 10).
-- Dedicated script imports from it using a relative path.
-- ============================================================
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock) VALUES (
'test-workspace',
'system',
E'def helper(x: int):\n return x * 10',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
'', '',
'f/system/py_dedicated_helper', 300062, 'python3', '');
INSERT INTO public.script(workspace_id, created_by, content, schema, summary, description, path, hash, language, lock, dedicated_worker) VALUES (
'test-workspace',
'system',
E'from .py_dedicated_helper import helper\n\ndef main(x: int):\n return helper(x) + 1',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
'', '',
'f/system/py_dedicated_with_import', 300063, 'python3', '', true);
-- ============================================================
-- Test: non-squashed for-loop in dedicated flow
-- For-loop iterates over [1, 2, 3], inner bun step returns iter.value * 10.
-- NOT squashed, so inner steps use the dedicated worker map (not flow runners).
-- ============================================================
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_forloop_flow',
'{3000000000000015}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"forloopflow","iterator":{"type":"javascript","expr":"[1, 2, 3]"},"skip_failures":false,"parallel":false,"squash":false,"modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(iter: {value: number, index: number}) { return iter.value * 10; }","language":"bun","input_transforms":{"iter":{"expr":"flow_input.iter","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000015,
'test-workspace',
'f/system/dedicated_forloop_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"forloopflow","iterator":{"type":"javascript","expr":"[1, 2, 3]"},"skip_failures":false,"parallel":false,"squash":false,"modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(iter: {value: number, index: number}) { return iter.value * 10; }","language":"bun","input_transforms":{"iter":{"expr":"flow_input.iter","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}}]}',
'system'
);
-- ============================================================
-- Test: non-simple for-loop in dedicated flow (multi-step)
-- For-loop iterates over [1, 2, 3], two steps: step b (iter.value + 1), step c (results.b * 10).
-- Two steps makes is_simple_modules false, so inner steps run as separate jobs.
-- ============================================================
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_forloop_multi_step_flow',
'{3000000000000019}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"forloopflow","iterator":{"type":"javascript","expr":"[1, 2, 3]"},"skip_failures":false,"parallel":false,"squash":false,"modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(iter: {value: number, index: number}) { return iter.value + 1; }","language":"bun","input_transforms":{"iter":{"expr":"flow_input.iter","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}},{"id":"c","value":{"type":"rawscript","content":"export function main(prev: number) { return prev * 10; }","language":"bun","input_transforms":{"prev":{"expr":"results.b","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000019,
'test-workspace',
'f/system/dedicated_forloop_multi_step_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"forloopflow","iterator":{"type":"javascript","expr":"[1, 2, 3]"},"skip_failures":false,"parallel":false,"squash":false,"modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(iter: {value: number, index: number}) { return iter.value + 1; }","language":"bun","input_transforms":{"iter":{"expr":"flow_input.iter","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}},{"id":"c","value":{"type":"rawscript","content":"export function main(prev: number) { return prev * 10; }","language":"bun","input_transforms":{"prev":{"expr":"results.b","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}}]}',
'system'
);
-- ============================================================
-- Test: while-loop in dedicated flow
-- While-loop with an inner bun step that returns x + 1.
-- Early stop breaks when result >= 3.
-- ============================================================
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_whileloop_flow',
'{3000000000000016}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"whileloopflow","skip_failures":false,"squash":false,"modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(n: number) { return n + 1; }","language":"bun","input_transforms":{"n":{"expr":"results.b ?? flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"},"stop_after_if":{"expr":"result >= 3","skip_if_stopped":false}}]}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000016,
'test-workspace',
'f/system/dedicated_whileloop_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"whileloopflow","skip_failures":false,"squash":false,"modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(n: number) { return n + 1; }","language":"bun","input_transforms":{"n":{"expr":"results.b ?? flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"},"stop_after_if":{"expr":"result >= 3","skip_if_stopped":false}}]}}]}',
'system'
);
-- ============================================================
-- Test: branchall in dedicated flow
-- BranchAll with 2 parallel branches, each with a bun step.
-- Branch 0: x + 100, Branch 1: x + 200.
-- ============================================================
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_branchall_flow',
'{3000000000000017}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"branchall","parallel":true,"branches":[{"expr":"true","modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(x: number) { return x + 100; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]},{"expr":"true","modules":[{"id":"c","value":{"type":"rawscript","content":"export function main(x: number) { return x + 200; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}]}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000017,
'test-workspace',
'f/system/dedicated_branchall_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{"x":{"type":"number","description":""}},"required":["x"],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"branchall","parallel":true,"branches":[{"expr":"true","modules":[{"id":"b","value":{"type":"rawscript","content":"export function main(x: number) { return x + 100; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]},{"expr":"true","modules":[{"id":"c","value":{"type":"rawscript","content":"export function main(x: number) { return x + 200; }","language":"bun","input_transforms":{"x":{"expr":"flow_input.x","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}]}}]}',
'system'
);
-- ============================================================
-- Test: nested branch inside loop in dedicated flow
-- For-loop [1,2] with inner branchone: if iter.value > 1 → x + 100, else → x + 200.
-- Tests deeply nested dispatch (forloop-N/branchone-0/step_id).
-- ============================================================
INSERT INTO public.flow(workspace_id, summary, description, path, versions, schema, value, edited_by) VALUES (
'test-workspace', '', '',
'f/system/dedicated_nested_flow',
'{3000000000000018}',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"forloopflow","iterator":{"type":"javascript","expr":"[1, 2]"},"skip_failures":false,"parallel":false,"squash":false,"modules":[{"id":"b","value":{"type":"branchone","branches":[{"expr":"flow_input.iter.value > 1","modules":[{"id":"c","value":{"type":"rawscript","content":"export function main(iter: {value: number}) { return iter.value + 100; }","language":"bun","input_transforms":{"iter":{"expr":"flow_input.iter","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}],"default":[{"id":"d","value":{"type":"rawscript","content":"export function main(iter: {value: number}) { return iter.value + 200; }","language":"bun","input_transforms":{"iter":{"expr":"flow_input.iter","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}}]}}]}',
'system'
);
INSERT INTO public.flow_version(id, workspace_id, path, schema, value, created_by) VALUES (
3000000000000018,
'test-workspace',
'f/system/dedicated_nested_flow',
'{"$schema":"https://json-schema.org/draft/2020-12/schema","properties":{},"required":[],"type":"object"}',
E'{"modules":[{"id":"a","value":{"type":"forloopflow","iterator":{"type":"javascript","expr":"[1, 2]"},"skip_failures":false,"parallel":false,"squash":false,"modules":[{"id":"b","value":{"type":"branchone","branches":[{"expr":"flow_input.iter.value > 1","modules":[{"id":"c","value":{"type":"rawscript","content":"export function main(iter: {value: number}) { return iter.value + 100; }","language":"bun","input_transforms":{"iter":{"expr":"flow_input.iter","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}],"default":[{"id":"d","value":{"type":"rawscript","content":"export function main(iter: {value: number}) { return iter.value + 200; }","language":"bun","input_transforms":{"iter":{"expr":"flow_input.iter","type":"javascript"}},"lock":"{}\\n//bun.lock\\n<empty>"}}]}}]}}]}',
'system'
);

View File

@@ -240,10 +240,7 @@ async fn test_from_db_worker_config_prefix_stripping(db: Pool<Postgres>) {
config.worker_configs.contains_key("my_group_name"),
"worker__ prefix should be stripped"
);
assert_eq!(
config.worker_configs["my_group_name"].extra["cache_clear"],
serde_json::json!(5)
);
assert_eq!(config.worker_configs["my_group_name"].extra["cache_clear"], serde_json::json!(5));
}
#[sqlx::test(fixtures("base"))]
@@ -403,11 +400,12 @@ async fn test_apply_settings_diff_complex_json(db: Pool<Postgres>) {
#[sqlx::test(fixtures("base"))]
async fn test_apply_settings_diff_delete_nonexistent_is_noop(db: Pool<Postgres>) {
let diff = SettingsDiff {
upserts: BTreeMap::new(),
deletes: vec!["does_not_exist".to_string()],
..Default::default()
};
let diff =
SettingsDiff {
upserts: BTreeMap::new(),
deletes: vec!["does_not_exist".to_string()],
..Default::default()
};
// Should not error
apply_settings_diff(&db, &diff).await.unwrap();
@@ -659,8 +657,11 @@ async fn test_roundtrip_to_settings_map_from_db_consistency(db: Pool<Postgres>)
};
let map = original.to_settings_map();
let diff =
SettingsDiff { upserts: map.into_iter().collect(), deletes: vec![], ..Default::default() };
let diff = SettingsDiff {
upserts: map.into_iter().collect(),
deletes: vec![],
..Default::default()
};
apply_settings_diff(&db, &diff).await.unwrap();
@@ -865,10 +866,7 @@ async fn test_full_config_roundtrip(db: Pool<Postgres>) {
assert_eq!(otel.tracing_enabled, Some(true));
assert_eq!(config.worker_configs.len(), 2);
assert_eq!(
config.worker_configs["default"].extra["cache_clear"],
serde_json::json!(7)
);
assert_eq!(config.worker_configs["default"].extra["cache_clear"], serde_json::json!(7));
let gpu_auto = config.worker_configs["gpu"].autoscaling.as_ref().unwrap();
assert!(gpu_auto.enabled);
assert_eq!(gpu_auto.min_workers, Some(0));
@@ -1008,146 +1006,3 @@ async fn test_replace_mode_protects_settings_in_integration(db: Pool<Postgres>)
Some(serde_json::json!("yes"))
);
}
// ========================================================================
// jwt_secret and rsa_keys declarative roundtrip
// ========================================================================
#[sqlx::test(fixtures("base"))]
async fn test_jwt_secret_roundtrip_as_string_or_secret_ref(db: Pool<Postgres>) {
clear_settings_and_configs(&db).await;
// Simulate what the operator does: parse a GlobalSettings with jwt_secret
// as a resolved StringOrSecretRef::Literal, write to DB, read back.
let settings = windmill_common::instance_config::GlobalSettings {
jwt_secret: Some(
windmill_common::instance_config::StringOrSecretRef::Literal(
"my-jwt-secret-from-k8s".to_string(),
),
),
..Default::default()
};
let map = settings.to_settings_map();
// The serialized form should be a plain JSON string (not an object)
assert_eq!(
map["jwt_secret"],
serde_json::json!("my-jwt-secret-from-k8s")
);
let diff =
SettingsDiff { upserts: map.into_iter().collect(), deletes: vec![], ..Default::default() };
apply_settings_diff(&db, &diff).await.unwrap();
// Read back from DB — jwt_secret should survive the roundtrip
let config = InstanceConfig::from_db(&db).await.unwrap();
assert_eq!(
config
.global_settings
.jwt_secret
.as_ref()
.and_then(|v| v.as_literal()),
Some("my-jwt-secret-from-k8s")
);
// Verify the raw DB value is a plain string (not wrapped in an object)
let raw = get_global_setting(&db, "jwt_secret").await.unwrap();
assert!(
raw.is_string(),
"jwt_secret in DB should be a plain JSON string"
);
assert_eq!(raw.as_str().unwrap(), "my-jwt-secret-from-k8s");
}
#[sqlx::test(fixtures("base"))]
async fn test_rsa_keys_roundtrip_via_extra(db: Pool<Postgres>) {
clear_settings_and_configs(&db).await;
// rsa_keys is not a typed field — it flows through GlobalSettings.extra.
// Simulate a resolved secretKeyRef: the operator resolves the ref and
// writes the plain value to extra before syncing to DB.
let json_str = r#"{
"rsa_keys": {
"private_key": "-----BEGIN RSA PRIVATE KEY-----\ntest-key-data\n-----END RSA PRIVATE KEY-----"
}
}"#;
let settings: windmill_common::instance_config::GlobalSettings =
serde_json::from_str(json_str).unwrap();
// rsa_keys should land in extra
assert!(settings.extra.contains_key("rsa_keys"));
let map = settings.to_settings_map();
let diff =
SettingsDiff { upserts: map.into_iter().collect(), deletes: vec![], ..Default::default() };
apply_settings_diff(&db, &diff).await.unwrap();
// Read back from DB
let config = InstanceConfig::from_db(&db).await.unwrap();
assert_eq!(
config.global_settings.extra["rsa_keys"]["private_key"],
"-----BEGIN RSA PRIVATE KEY-----\ntest-key-data\n-----END RSA PRIVATE KEY-----"
);
// Verify the raw DB value is a JSON object with private_key
let raw = get_global_setting(&db, "rsa_keys").await.unwrap();
assert!(raw.is_object());
assert_eq!(
raw["private_key"].as_str().unwrap(),
"-----BEGIN RSA PRIVATE KEY-----\ntest-key-data\n-----END RSA PRIVATE KEY-----"
);
}
#[sqlx::test(fixtures("base"))]
async fn test_replace_mode_protects_jwt_secret_and_rsa_keys(db: Pool<Postgres>) {
clear_settings_and_configs(&db).await;
// Seed jwt_secret and rsa_keys (both are PROTECTED_SETTINGS)
insert_global_setting(&db, "jwt_secret", serde_json::json!("existing-secret")).await;
insert_global_setting(
&db,
"rsa_keys",
serde_json::json!({"private_key": "existing-rsa-key"}),
)
.await;
insert_global_setting(&db, "normal_setting", serde_json::json!("will-go")).await;
let config = InstanceConfig::from_db(&db).await.unwrap();
let current_map = config.global_settings.to_settings_map();
// Desired state: only base_url — jwt_secret and rsa_keys should survive
let mut desired_map = BTreeMap::new();
desired_map.insert(
"base_url".to_string(),
serde_json::json!("https://example.com"),
);
let diff = diff_global_settings(&current_map, &desired_map, ApplyMode::Replace);
assert!(
!diff.deletes.contains(&"jwt_secret".to_string()),
"jwt_secret is protected from deletion"
);
assert!(
!diff.deletes.contains(&"rsa_keys".to_string()),
"rsa_keys is protected from deletion"
);
assert!(
diff.deletes.contains(&"normal_setting".to_string()),
"normal_setting should be deleted"
);
apply_settings_diff(&db, &diff).await.unwrap();
// Both protected settings survive
assert_eq!(
get_global_setting(&db, "jwt_secret").await,
Some(serde_json::json!("existing-secret"))
);
assert_eq!(
get_global_setting(&db, "rsa_keys").await,
Some(serde_json::json!({"private_key": "existing-rsa-key"}))
);
assert!(get_global_setting(&db, "normal_setting").await.is_none());
}

View File

@@ -49,7 +49,7 @@ mod job_payload {
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
debouncing_settings:
windmill_common::runnable_settings::DebouncingSettings::default(), labels: None,
windmill_common::runnable_settings::DebouncingSettings::default(),
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
@@ -89,7 +89,7 @@ mod job_payload {
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default(),
debouncing_settings:
windmill_common::runnable_settings::DebouncingSettings::default(), labels: None,
windmill_common::runnable_settings::DebouncingSettings::default(),
})
.run_until_complete_with(db, false, port, |id| async move {
let job = sqlx::query!("SELECT preprocessed FROM v2_job WHERE id = $1", id)
@@ -424,7 +424,7 @@ mod job_payload {
path: "f/system/hello_with_nodes_flow".to_string(),
dedicated_worker: None,
apply_preprocessor: false,
version: 1443253234253454, labels: None,
version: 1443253234253454,
})
.run_until_complete(&db, false, port)
.await
@@ -473,7 +473,7 @@ mod job_payload {
path: "f/system/hello_with_preprocessor".to_string(),
dedicated_worker: None,
apply_preprocessor: true,
version: 1443253234253456, labels: None,
version: 1443253234253456,
})
.run_until_complete_with(db, false, port, |id| async move {
let job = sqlx::query!("SELECT preprocessed FROM v2_job WHERE id = $1", id)
@@ -543,7 +543,7 @@ mod job_payload {
path: "f/system/hello_with_nodes_flow".to_string(),
dedicated_worker: None,
apply_preprocessor: true,
version: 1443253234253454, labels: None,
version: 1443253234253454,
})
.run_until_complete(&db, false, port)
.await
@@ -789,7 +789,7 @@ mod job_payload {
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default(),
debouncing_settings:
windmill_common::runnable_settings::DebouncingSettings::default(), labels: None,
windmill_common::runnable_settings::DebouncingSettings::default(),
})
.arg("foo", json!("hello"))
.arg("bar", json!("world"))
@@ -839,7 +839,7 @@ mod job_payload {
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default(),
debouncing_settings:
windmill_common::runnable_settings::DebouncingSettings::default(), labels: None,
windmill_common::runnable_settings::DebouncingSettings::default(),
})
.arg("foo", json!("hello"))
.arg("bar", json!("world"))
@@ -889,7 +889,7 @@ mod job_payload {
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default(),
debouncing_settings:
windmill_common::runnable_settings::DebouncingSettings::default(), labels: None,
windmill_common::runnable_settings::DebouncingSettings::default(),
})
.arg("foo", json!("hello"))
.arg("bar", json!("world"))
@@ -939,7 +939,7 @@ mod job_payload {
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default(),
debouncing_settings:
windmill_common::runnable_settings::DebouncingSettings::default(), labels: None,
windmill_common::runnable_settings::DebouncingSettings::default(),
})
.arg("foo", json!("hello"))
.arg("bar", json!("world"))
@@ -991,7 +991,7 @@ mod job_payload {
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default(),
debouncing_settings:
windmill_common::runnable_settings::DebouncingSettings::default(), labels: None,
windmill_common::runnable_settings::DebouncingSettings::default(),
})
.arg("foo", json!("hello"))
.arg("bar", json!("world"))

View File

@@ -64,8 +64,8 @@ async fn test_list_jobs_without_include_args(db: Pool<Postgres>) -> anyhow::Resu
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -121,8 +121,8 @@ async fn test_list_jobs_with_include_args(db: Pool<Postgres>) -> anyhow::Result<
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -192,8 +192,8 @@ async fn test_list_jobs_completed_with_include_args(db: Pool<Postgres>) -> anyho
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -265,8 +265,8 @@ async fn test_list_jobs_mixed_queue_and_completed(db: Pool<Postgres>) -> anyhow:
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -286,8 +286,8 @@ async fn test_list_jobs_mixed_queue_and_completed(db: Pool<Postgres>) -> anyhow:
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -349,9 +349,7 @@ async fn test_list_jobs_mixed_queue_and_completed(db: Pool<Postgres>) -> anyhow:
/// Test list_jobs with multiple queued jobs and include_args
#[sqlx::test(fixtures("base"))]
async fn test_list_jobs_multiple_queued_with_include_args(
db: Pool<Postgres>,
) -> anyhow::Result<()> {
async fn test_list_jobs_multiple_queued_with_include_args(db: Pool<Postgres>) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
@@ -371,8 +369,8 @@ async fn test_list_jobs_multiple_queued_with_include_args(
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -389,8 +387,8 @@ async fn test_list_jobs_multiple_queued_with_include_args(
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -413,13 +411,9 @@ async fn test_list_jobs_multiple_queued_with_include_args(
let jobs: Vec<ListJobsResponse> = response.json().await?;
// Find both jobs
let job1 = jobs
.iter()
.find(|j| j.id == job1_id.to_string())
let job1 = jobs.iter().find(|j| j.id == job1_id.to_string())
.expect("should find job1");
let job2 = jobs
.iter()
.find(|j| j.id == job2_id.to_string())
let job2 = jobs.iter().find(|j| j.id == job2_id.to_string())
.expect("should find job2");
// Both should have args
@@ -467,8 +461,8 @@ async fn test_queue_list_without_include_args(db: Pool<Postgres>) -> anyhow::Res
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -486,7 +480,10 @@ async fn test_queue_list_without_include_args(db: Pool<Postgres>) -> anyhow::Res
.send()
.await?;
assert!(response.status().is_success(), "queue/list should succeed");
assert!(
response.status().is_success(),
"queue/list should succeed"
);
let jobs: Vec<QueueJobResponse> = response.json().await?;
@@ -527,8 +524,8 @@ async fn test_queue_list_with_include_args(db: Pool<Postgres>) -> anyhow::Result
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -597,8 +594,8 @@ async fn test_queue_list_multiple_jobs_with_include_args(db: Pool<Postgres>) ->
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -615,8 +612,8 @@ async fn test_queue_list_multiple_jobs_with_include_args(db: Pool<Postgres>) ->
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -634,7 +631,10 @@ async fn test_queue_list_multiple_jobs_with_include_args(db: Pool<Postgres>) ->
.send()
.await?;
assert!(response.status().is_success(), "queue/list should succeed");
assert!(
response.status().is_success(),
"queue/list should succeed"
);
let jobs: Vec<QueueJobResponse> = response.json().await?;
@@ -694,8 +694,8 @@ async fn test_completed_list_without_include_args(db: Pool<Postgres>) -> anyhow:
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -760,8 +760,8 @@ async fn test_completed_list_with_include_args(db: Pool<Postgres>) -> anyhow::Re
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -835,8 +835,8 @@ async fn test_completed_list_multiple_jobs_with_include_args(
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -856,8 +856,8 @@ async fn test_completed_list_multiple_jobs_with_include_args(
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
concurrency_settings:
windmill_common::runnable_settings::ConcurrencySettings::default().into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
@@ -912,273 +912,3 @@ async fn test_completed_list_multiple_jobs_with_include_args(
Ok(())
}
// =============================================================================
// Labels integration tests
// =============================================================================
#[sqlx::test(fixtures("base"))]
async fn test_job_labels_propagated_at_push_time(db: Pool<Postgres>) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
let port = server.addr.port();
let client = windmill_api_client::create_client(
&format!("http://localhost:{port}"),
"SECRET_TOKEN".to_string(),
);
// Push a script job with labels
let job_id = RunJob::from(JobPayload::ScriptHash {
hash: windmill_common::scripts::ScriptHash(0),
path: "u/admin/test_labels_script".to_string(),
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
language: ScriptLang::Python3,
priority: None,
apply_preprocessor: false,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
labels: Some(vec!["prod".to_string(), "deploy".to_string()]),
})
.push(&db)
.await;
// Verify labels in queue listing
let response = client
.client()
.get(format!("{}/w/test-workspace/jobs/list", client.baseurl()))
.send()
.await?;
assert!(response.status().is_success());
let jobs: Vec<serde_json::Value> = response.json().await?;
let job = jobs
.iter()
.find(|j| j["id"].as_str() == Some(&job_id.to_string()))
.expect("should find job");
let labels = job["labels"].as_array().expect("labels should be an array");
assert!(labels.contains(&json!("prod")));
assert!(labels.contains(&json!("deploy")));
Ok(())
}
#[sqlx::test(fixtures("base"))]
async fn test_job_without_labels_has_no_labels_field(db: Pool<Postgres>) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
let port = server.addr.port();
let client = windmill_api_client::create_client(
&format!("http://localhost:{port}"),
"SECRET_TOKEN".to_string(),
);
// Push a job without labels
let job_id = RunJob::from(JobPayload::Code(RawCode {
hash: None,
content: "def main(): return 1".to_string(),
path: None,
language: ScriptLang::Python3,
lock: None,
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}))
.push(&db)
.await;
let response = client
.client()
.get(format!("{}/w/test-workspace/jobs/list", client.baseurl()))
.send()
.await?;
assert!(response.status().is_success());
let jobs: Vec<serde_json::Value> = response.json().await?;
let job = jobs
.iter()
.find(|j| j["id"].as_str() == Some(&job_id.to_string()))
.expect("should find job");
// Labels should be null/missing for jobs without labels
assert!(
job.get("labels").is_none() || job["labels"].is_null(),
"job without labels should not have labels field"
);
Ok(())
}
#[sqlx::test(fixtures("base"))]
async fn test_job_label_filter(db: Pool<Postgres>) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
let port = server.addr.port();
let client = windmill_api_client::create_client(
&format!("http://localhost:{port}"),
"SECRET_TOKEN".to_string(),
);
// Push two jobs with different labels, then complete them via SQL
// Label filtering only works on completed jobs
let job_prod_id = RunJob::from(JobPayload::ScriptHash {
hash: windmill_common::scripts::ScriptHash(0),
path: "u/admin/prod_script".to_string(),
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
language: ScriptLang::Bun,
priority: None,
apply_preprocessor: false,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
labels: Some(vec!["prod".to_string()]),
})
.push(&db)
.await;
let job_staging_id = RunJob::from(JobPayload::ScriptHash {
hash: windmill_common::scripts::ScriptHash(0),
path: "u/admin/staging_script".to_string(),
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
language: ScriptLang::Bun,
priority: None,
apply_preprocessor: false,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
labels: Some(vec!["staging".to_string()]),
})
.push(&db)
.await;
// Complete both jobs directly via SQL so label filter can find them
for job_id in &[job_prod_id, job_staging_id] {
sqlx::query(
"INSERT INTO v2_job_completed (workspace_id, id, result, status, duration_ms) VALUES ('test-workspace', $1, '{}'::jsonb, 'success', 0)",
)
.bind(job_id)
.execute(&db)
.await?;
}
// Filter by label=prod
let response = client
.client()
.get(format!(
"{}/w/test-workspace/jobs/list?label=prod",
client.baseurl()
))
.send()
.await?;
assert!(response.status().is_success());
let jobs: Vec<serde_json::Value> = response.json().await?;
// Should find the prod job
assert!(
jobs.iter()
.any(|j| j["id"].as_str() == Some(&job_prod_id.to_string())),
"prod job should appear in label=prod filter"
);
// Should NOT find the staging job
assert!(
!jobs
.iter()
.any(|j| j["id"].as_str() == Some(&job_staging_id.to_string())),
"staging job should not appear in label=prod filter"
);
Ok(())
}
#[sqlx::test(fixtures("base"))]
async fn test_wm_labels_from_result_merged_with_static_labels(
db: Pool<Postgres>,
) -> anyhow::Result<()> {
initialize_tracing().await;
let server = ApiServer::start(db.clone()).await?;
let port = server.addr.port();
let client = windmill_api_client::create_client(
&format!("http://localhost:{port}"),
"SECRET_TOKEN".to_string(),
);
// Use Code(RawCode) to run a Bun script that returns wm_labels,
// then set static labels on the job row before execution
let job = RunJob::from(JobPayload::Code(RawCode {
hash: None,
content: r#"export async function main() { return { wm_labels: ["runtime-label"] }; }"#
.to_string(),
path: None,
language: ScriptLang::Bun,
lock: None,
cache_ttl: None,
cache_ignore_s3_path: None,
dedicated_worker: None,
concurrency_settings: windmill_common::runnable_settings::ConcurrencySettings::default()
.into(),
debouncing_settings: windmill_common::runnable_settings::DebouncingSettings::default(),
modules: None,
}));
let completed = job
.run_until_complete_with(&db, false, port, |uuid| {
let db = db.clone();
async move {
// Set static labels before the worker picks up the job
sqlx::query(
"UPDATE v2_job SET labels = ARRAY['static-label']::text[] WHERE id = $1",
)
.bind(uuid)
.execute(&db)
.await
.expect("should set labels");
}
})
.await;
// Fetch the job via API and check labels
let response = client
.client()
.get(format!(
"{}/w/test-workspace/jobs_u/get/{}",
client.baseurl(),
completed.id
))
.send()
.await?;
assert!(response.status().is_success());
let job: serde_json::Value = response.json().await?;
let labels = job["labels"].as_array().expect("labels should be an array");
// Should contain both the static label and runtime label from wm_labels
assert!(
labels.contains(&json!("static-label")),
"should contain static label set at push time, got: {:?}",
labels
);
assert!(
labels.contains(&json!("runtime-label")),
"should contain runtime label from wm_labels in result, got: {:?}",
labels
);
Ok(())
}

View File

@@ -445,89 +445,4 @@ mod tests {
Some(serde_json::json!("value"))
);
}
// ========================================================================
// jwt_secret and rsa_keys via sync_global_settings
// ========================================================================
#[sqlx::test(fixtures("base"))]
async fn test_sync_jwt_secret_via_settings_map(db: Pool<Postgres>) {
// Simulate the full operator pipeline: parse GlobalSettings with a
// resolved jwt_secret (StringOrSecretRef::Literal), convert to
// settings map, and sync to DB.
let settings = windmill_common::instance_config::GlobalSettings {
jwt_secret: Some(
windmill_common::instance_config::StringOrSecretRef::Literal(
"resolved-jwt-value".to_string(),
),
),
..Default::default()
};
let map = settings.to_settings_map();
windmill_operator::db_sync::sync_global_settings(&db, &map)
.await
.expect("sync should succeed");
let stored = get_global_setting(&db, "jwt_secret")
.await
.expect("jwt_secret should exist");
assert_eq!(stored, serde_json::json!("resolved-jwt-value"));
}
#[sqlx::test(fixtures("base"))]
async fn test_sync_rsa_keys_via_settings_map(db: Pool<Postgres>) {
// rsa_keys flows through GlobalSettings.extra as opaque JSON.
// After operator resolves secretKeyRef, the value is a plain JSON
// object that gets synced to DB.
let json_str = r#"{
"rsa_keys": {
"private_key": "-----BEGIN RSA PRIVATE KEY-----\ntest\n-----END RSA PRIVATE KEY-----"
}
}"#;
let settings: windmill_common::instance_config::GlobalSettings =
serde_json::from_str(json_str).unwrap();
let map = settings.to_settings_map();
windmill_operator::db_sync::sync_global_settings(&db, &map)
.await
.expect("sync should succeed");
let stored = get_global_setting(&db, "rsa_keys")
.await
.expect("rsa_keys should exist");
assert_eq!(
stored["private_key"],
"-----BEGIN RSA PRIVATE KEY-----\ntest\n-----END RSA PRIVATE KEY-----"
);
}
#[sqlx::test(fixtures("base"))]
async fn test_sync_protects_jwt_secret_and_rsa_keys(db: Pool<Postgres>) {
// Pre-populate both protected settings
insert_global_setting(&db, "jwt_secret", serde_json::json!("original-jwt")).await;
insert_global_setting(
&db,
"rsa_keys",
serde_json::json!({"private_key": "original-rsa"}),
)
.await;
// Sync with empty desired — protected keys should survive
let desired = BTreeMap::new();
windmill_operator::db_sync::sync_global_settings(&db, &desired)
.await
.expect("sync should succeed");
assert_eq!(
get_global_setting(&db, "jwt_secret").await,
Some(serde_json::json!("original-jwt")),
"jwt_secret is protected and should survive empty sync"
);
assert_eq!(
get_global_setting(&db, "rsa_keys").await,
Some(serde_json::json!({"private_key": "original-rsa"})),
"rsa_keys is protected and should survive empty sync"
);
}
}

View File

@@ -227,8 +227,6 @@ mod dedicated_worker_protocol_python {
enum ProtocolCmd {
Exec { path: String, args: serde_json::Value },
ExecPreprocess { path: String, args: serde_json::Value },
Execd { args: serde_json::Value },
ExecdPreprocess { args: serde_json::Value },
}
/// Run a Python worker test with raw protocol commands
@@ -267,15 +265,13 @@ mod dedicated_worker_protocol_python {
ProtocolCmd::ExecPreprocess { path, args } => {
format!("exec_preprocess:{}:{}", path, args)
}
ProtocolCmd::Execd { args } => format!("execd:{}", args),
ProtocolCmd::ExecdPreprocess { args } => format!("execd_preprocess:{}", args),
};
writeln!(stdin, "{}", line).unwrap();
stdin.flush().unwrap();
let expected_lines = match cmd {
ProtocolCmd::ExecPreprocess { .. } | ProtocolCmd::ExecdPreprocess { .. } => 2,
ProtocolCmd::Exec { .. } | ProtocolCmd::Execd { .. } => 1,
ProtocolCmd::ExecPreprocess { .. } => 2,
ProtocolCmd::Exec { .. } => 1,
};
for _ in 0..expected_lines {
@@ -378,93 +374,6 @@ def main(x: int):
);
}
// ==================== execd / execd_preprocess Tests ====================
#[test]
fn test_python_execd_single_script() {
let results = run_py_raw_protocol_test(
&[(
"f/test/add",
"def main(a: int, b: int):\n return a + b\n",
)],
vec![ProtocolCmd::Execd { args: serde_json::json!({"a": 3, "b": 4}) }],
);
assert_eq!(results.len(), 1);
assert_eq!(
results[0],
DedicatedWorkerResult::Success(serde_json::json!(7))
);
}
#[test]
fn test_python_execd_preprocess() {
let script = r#"
def preprocessor(x: int):
return {"x": x * 10}
def main(x: int):
return x + 1
"#;
let results = run_py_raw_protocol_test(
&[("f/test/pre", script)],
vec![ProtocolCmd::ExecdPreprocess { args: serde_json::json!({"x": 5}) }],
);
assert_eq!(results.len(), 2);
assert_eq!(
results[0],
DedicatedWorkerResult::PreprocessedArgs(serde_json::json!({"x": 50}))
);
// main(50) => 51
assert_eq!(
results[1],
DedicatedWorkerResult::Success(serde_json::json!(51))
);
}
#[test]
fn test_python_execd_preprocess_missing_preprocessor() {
let script = "def main(x: int):\n return x\n";
let results = run_py_raw_protocol_test(
&[("f/test/nopre", script)],
vec![ProtocolCmd::ExecdPreprocess { args: serde_json::json!({"x": 5}) }],
);
assert_eq!(results.len(), 1);
assert!(matches!(results[0], DedicatedWorkerResult::Error(_)));
}
#[test]
fn test_python_execd_preprocess_then_execd() {
let script = r#"
def preprocessor(x: int):
return {"x": x * 2}
def main(x: int):
return x + 100
"#;
let results = run_py_raw_protocol_test(
&[("f/test/mixed", script)],
vec![
ProtocolCmd::ExecdPreprocess { args: serde_json::json!({"x": 5}) },
ProtocolCmd::Execd { args: serde_json::json!({"x": 7}) },
],
);
// preprocess: preprocessor(5) => {"x":10}, main(10) => 110
// execd: main(7) => 107
assert_eq!(results.len(), 3);
assert_eq!(
results[0],
DedicatedWorkerResult::PreprocessedArgs(serde_json::json!({"x": 10}))
);
assert_eq!(
results[1],
DedicatedWorkerResult::Success(serde_json::json!(110))
);
assert_eq!(
results[2],
DedicatedWorkerResult::Success(serde_json::json!(107))
);
}
// ==================== Argument Transformation Tests ====================
#[test]

View File

@@ -101,9 +101,7 @@ mod relock_skip {
before
}
// Requires `private` feature for the dependency job concurrency limit that prevents
// race conditions between concurrent dep jobs for the same flow/app.
#[cfg(all(feature = "python", feature = "private"))]
#[cfg(feature = "python")]
#[sqlx::test(fixtures("base", "dependency_map"))]
async fn relock_skip_on_script_redeployment(db: Pool<Postgres>) -> anyhow::Result<()> {
std::env::set_var("DEPENDENCY_JOB_DEBOUNCE_DELAY", "0");
@@ -130,9 +128,8 @@ def main():
.await
.unwrap();
// leaf_1(1) + branch(1) + root_script(1-2) + root_flow(1-2) + root_app(1-2) = 5-8 jobs
// With debouncing (private feature), duplicate dep jobs from branch cascade may be coalesced.
wait_for_jobs_ge(&mut completed, 5).await;
// leaf_1(1) + branch(1) + root_script(2: leaf_1+branch) + root_flow(2) + root_app(2) = 8 jobs
wait_for_jobs(&mut completed, 8).await;
let skipping_count = count_pattern_in_job_logs(&db, "Skipping relock", before).await;
let relocking_count = count_pattern_in_job_logs(&db, "Relocking", before).await;
@@ -239,9 +236,7 @@ def main():
Ok(())
}
// Requires `private` feature for the dependency job concurrency limit that prevents
// race conditions between concurrent dep jobs for the same flow/app.
#[cfg(all(feature = "python", feature = "private"))]
#[cfg(feature = "python")]
#[sqlx::test(fixtures("base", "dependency_map"))]
async fn relock_skip_on_workspace_deps_redeployment(db: Pool<Postgres>) -> anyhow::Result<()> {
use windmill_common::scripts::ScriptLang;

Some files were not shown because too many files have changed in this diff Show More