mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-06 16:02:23 +00:00
Merge branch 'main' into claude/issue-6832-20251015-1048
This commit is contained in:
@@ -69,11 +69,10 @@ jobs:
|
||||
./substitute_ee_code.sh --copy --dir ./windmill-ee-private
|
||||
- name: cargo test
|
||||
timeout-minutes: 16
|
||||
run:
|
||||
deno --version && bun -v && go version && python3 --version &&
|
||||
run: deno --version && bun -v && go version && python3 --version &&
|
||||
SQLX_OFFLINE=true
|
||||
DATABASE_URL=postgres://postgres:changeme@localhost:5432/windmill
|
||||
DISABLE_EMBEDDING=true RUST_LOG=info
|
||||
DISABLE_EMBEDDING=true RUST_LOG=info RUST_LOG_STYLE=never
|
||||
DENO_PATH=$(which deno) BUN_PATH=$(which bun) GO_PATH=$(which go)
|
||||
UV_PATH=$(which uv) cargo test --features
|
||||
enterprise,deno_core,license,python,rust,scoped_cache,private --all --
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"svelte": {
|
||||
"type": "http",
|
||||
"url": "https://mcp.svelte.dev/mcp"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,51 @@
|
||||
# Changelog
|
||||
|
||||
## [1.562.0](https://github.com/windmill-labs/windmill/compare/v1.561.0...v1.562.0) (2025-10-16)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add support for sage intacct oauth ([#6794](https://github.com/windmill-labs/windmill/issues/6794)) ([c86b344](https://github.com/windmill-labs/windmill/commit/c86b3448b86e008f14a25280285cc2f498eb926a))
|
||||
* dependency job debouncing ([#6769](https://github.com/windmill-labs/windmill/issues/6769)) ([defb6c9](https://github.com/windmill-labs/windmill/commit/defb6c9694ac294dbf19ba5cd42ce7399ad1b9ac))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add configurable timeout sse stream ([f723a1f](https://github.com/windmill-labs/windmill/commit/f723a1fb7227ae45661fea5cf2e6f9928a39672b))
|
||||
|
||||
## [1.561.0](https://github.com/windmill-labs/windmill/compare/v1.560.0...v1.561.0) (2025-10-16)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* ansible playbook execution git repo mode (repo viewer + UI utils) ([#6831](https://github.com/windmill-labs/windmill/issues/6831)) ([32fae7a](https://github.com/windmill-labs/windmill/commit/32fae7a10c769473c708970e18c1f8268d62183f))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **backend:** revert flow node opti for ai agents ([#6840](https://github.com/windmill-labs/windmill/issues/6840)) ([3b5c962](https://github.com/windmill-labs/windmill/commit/3b5c96247350b70fe947d204e9bff61f81be219c))
|
||||
* fix job loader in public apps with jwt token ([a238750](https://github.com/windmill-labs/windmill/commit/a2387505544a04675a7c9fddf2ed8c042f8bfa42))
|
||||
|
||||
## [1.560.0](https://github.com/windmill-labs/windmill/compare/v1.559.0...v1.560.0) (2025-10-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add support for zoho oauth ([#6809](https://github.com/windmill-labs/windmill/issues/6809)) ([9d9c29f](https://github.com/windmill-labs/windmill/commit/9d9c29fdfa15cc655854ec909dea944d10ce7374))
|
||||
* **backend:** use flow nodes opti for ai agent steps ([#6808](https://github.com/windmill-labs/windmill/issues/6808)) ([8d5acda](https://github.com/windmill-labs/windmill/commit/8d5acda340cd105c5b0dfc2bfe59b7e996bd2707))
|
||||
* build pydoc for wmill python client and mount in container image ([#6828](https://github.com/windmill-labs/windmill/issues/6828)) ([d75e9e3](https://github.com/windmill-labs/windmill/commit/d75e9e3d92d43f449a6296b367018f8fa3da6507))
|
||||
* **settings:** add unsaved changes warning for workspace settings ([#6813](https://github.com/windmill-labs/windmill/issues/6813)) ([cb88187](https://github.com/windmill-labs/windmill/commit/cb8818796ddd68d2b2ee1dea5f9b0a648f0c1ec9))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* always create instance groups with uuid ([#6826](https://github.com/windmill-labs/windmill/issues/6826)) ([48acc57](https://github.com/windmill-labs/windmill/commit/48acc57823792c9e795f9735712e1b2ed6d2b4e2))
|
||||
* bug for loop flow inconsistent state ([#6815](https://github.com/windmill-labs/windmill/issues/6815)) ([2565222](https://github.com/windmill-labs/windmill/commit/256522273ee65b67075ac91408825b1c6e91ef06))
|
||||
* fix concurrency key filter ([892ce64](https://github.com/windmill-labs/windmill/commit/892ce64ea8550c22d65180c71f57c90a65583832))
|
||||
* gcp script picker ([#6837](https://github.com/windmill-labs/windmill/issues/6837)) ([d12c8f3](https://github.com/windmill-labs/windmill/commit/d12c8f34efe5ebbdbbf85ae41bb11307dc5d8ea3))
|
||||
* resource editor should not autoselect resources for optional fields ([#6821](https://github.com/windmill-labs/windmill/issues/6821)) ([85d1b8a](https://github.com/windmill-labs/windmill/commit/85d1b8a3e6af41bba93128ebcb88ada383ed2d65))
|
||||
* support dyn select for sub flow ([#6835](https://github.com/windmill-labs/windmill/issues/6835)) ([b211155](https://github.com/windmill-labs/windmill/commit/b211155784135b1377975a2759f2ddca1cffcea2))
|
||||
|
||||
## [1.559.0](https://github.com/windmill-labs/windmill/compare/v1.558.1...v1.559.0) (2025-10-14)
|
||||
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ COPY /backend/windmill-api/build_openapi.sh /backend/windmill-api/build_openapi.
|
||||
RUN cd /backend/windmill-api && . ./build_openapi.sh
|
||||
COPY /backend/parsers/windmill-parser-wasm/pkg/ /backend/parsers/windmill-parser-wasm/pkg/
|
||||
COPY /typescript-client/docs/ /frontend/static/tsdocs/
|
||||
COPY /python-client/docs/ /frontend/static/pydocs/
|
||||
|
||||
RUN npm run generate-backend-client
|
||||
ENV NODE_OPTIONS "--max-old-space-size=8192"
|
||||
|
||||
+5
-5
@@ -46,11 +46,11 @@
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
]
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO deployment_metadata (workspace_id, path, script_hash, deployment_msg) VALUES ($1, $2, $3, $4) ON CONFLICT (workspace_id, script_hash) WHERE script_hash IS NOT NULL DO UPDATE SET deployment_msg = $4",
|
||||
"query": "INSERT INTO deployment_metadata (workspace_id, path, script_hash, deployment_msg) VALUES ($1, $2, $3, $4) ON CONFLICT (workspace_id, script_hash) WHERE script_hash IS NOT NULL\n DO UPDATE SET deployment_msg = EXCLUDED.deployment_msg",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -13,5 +13,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "db558b5ecdc4c3b1af0def511f1bcd91a548f00376f644c8ba38f73812b462d0"
|
||||
"hash": "07335b75233811352fb898cf3d6c8fe7fd014adbf40cc4bc8c041f5864423367"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO global_settings (name, value) VALUES ($1, $2) ON CONFLICT (name) DO UPDATE SET value = $2, updated_at = now()",
|
||||
"query": "INSERT INTO global_settings (name, value) VALUES ($1, $2) ON CONFLICT (name) DO UPDATE SET value = EXCLUDED.value, updated_at = now()",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -11,5 +11,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "a59b70164dc87224d09a04d5469ca217eb19a15a250c3b83ca63f606f89b9681"
|
||||
"hash": "08c1121171b98889f188ea6b33b1861f3483fa70b5d58dd2838a5cb6dabe9cc1"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO resource\n (workspace_id, path, value, resource_type, created_by, edited_at)\n VALUES ($1, $2, $3, $4, $5, now()) ON CONFLICT (workspace_id, path)\n DO UPDATE SET value = $3, edited_at = now()",
|
||||
"query": "INSERT INTO resource\n (workspace_id, path, value, resource_type, created_by, edited_at)\n VALUES ($1, $2, $3, $4, $5, now()) ON CONFLICT (workspace_id, path)\n DO UPDATE SET value = EXCLUDED.value, edited_at = now()",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -14,5 +14,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "8bd028c8b5f8a4d566f89eebc2e63fd04beaf2b0b49e07c7df42ecddd70737f3"
|
||||
"hash": "19e4625de06b8bab10039280a6213df5f38fb8892226f04cf700f60eb45199ef"
|
||||
}
|
||||
+1
-3
@@ -59,9 +59,7 @@
|
||||
"failure",
|
||||
"command",
|
||||
"approval",
|
||||
"preprocessor",
|
||||
"schedule_handler_old",
|
||||
"dynamic_skip"
|
||||
"preprocessor"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO variable\n (workspace_id, path, value, is_secret, account, is_oauth)\n VALUES ($1, $2, $3, $4, $5, $6)\n ON CONFLICT (workspace_id, path) DO UPDATE SET value = $3",
|
||||
"query": "INSERT INTO variable\n (workspace_id, path, value, is_secret, account, is_oauth)\n VALUES ($1, $2, $3, $4, $5, $6)\n ON CONFLICT (workspace_id, path) DO UPDATE SET value = EXCLUDED.value",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -15,5 +15,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "9f1f388924176dbe3dea882e0c62728a82ba256029096812dd705ccb1a552cfe"
|
||||
"hash": "1e426c8a06d7bbed7af67a105f74b3e03bd44048af4d69fab854f97fa821649b"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO global_settings (name, value) VALUES ($1, $2) ON CONFLICT (name) DO UPDATE SET value = $2",
|
||||
"query": "INSERT INTO global_settings (name, value) VALUES ($1, $2) ON CONFLICT (name) DO UPDATE SET value = EXCLUDED.value",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -11,5 +11,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "a00e61e770e20157bbd9e4cdedf7fb5f9de7c8c9e50282e3ecf2e3ce917ec37a"
|
||||
"hash": "24f38f0642b49626c8c8417e1846ab38dfe15284a6a7f54366ba25d7eb75a74a"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO config (name, config) VALUES ($1, $2) ON CONFLICT (name) DO UPDATE SET config = $2",
|
||||
"query": "INSERT INTO config (name, config) VALUES ($1, $2) ON CONFLICT (name) DO UPDATE SET config = EXCLUDED.config",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -11,5 +11,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "af00c212f509076e37538be52f582ba09e47db50ba93af322649ccddbb05cc49"
|
||||
"hash": "25bf02e605e9e8e708a5dcfbb898b1af55045c1b8c2a138ca995882dde955971"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO variable\n (workspace_id, path, value, is_secret, description, account, is_oauth)\n VALUES ($1, $2, $3, $4, $5, $6, $7)\n ON CONFLICT (workspace_id, path) DO UPDATE SET value = $3",
|
||||
"query": "INSERT INTO variable\n (workspace_id, path, value, is_secret, description, account, is_oauth)\n VALUES ($1, $2, $3, $4, $5, $6, $7)\n ON CONFLICT (workspace_id, path) DO UPDATE SET value = EXCLUDED.value",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -16,5 +16,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "55a2f170823f1d1abce76287d8817a6cf34de92b9b4079c00b75423a9ff835b9"
|
||||
"hash": "2b34ae324f90924dba6c4562024f72e7b051adb368b3685181047f1f4522a473"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO deployment_metadata (workspace_id, path, script_hash, callback_job_ids, deployment_msg) VALUES ($1, $2, $3, $4, $5) \n ON CONFLICT (workspace_id, script_hash) WHERE script_hash IS NOT NULL DO UPDATE SET callback_job_ids = $4, deployment_msg = $5",
|
||||
"query": "INSERT INTO deployment_metadata (workspace_id, path, script_hash, callback_job_ids, deployment_msg) VALUES ($1, $2, $3, $4, $5) \n ON CONFLICT (workspace_id, script_hash) WHERE script_hash IS NOT NULL DO UPDATE SET callback_job_ids = EXCLUDED.callback_job_ids, deployment_msg = EXCLUDED.deployment_msg",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -14,5 +14,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "8d119104337bf99e9aa9dcbac0a54154267a7db96cc0fb3ebaac95635e24da29"
|
||||
"hash": "2e131a019051bdac7c9c65f7c504cfba31cfdd64a0f68001e123694ed5cde5ed"
|
||||
}
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO instance_group (name, summary) VALUES ($1, $2) ON CONFLICT DO NOTHING",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Varchar"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "383b8adaadc6e23952ca8942fe7dbaa7c74ce0cfa1b945b7514e19a70f7a6f1c"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO deployment_metadata (workspace_id, path, app_version, deployment_msg) VALUES ($1, $2, $3, $4) ON CONFLICT (workspace_id, path, app_version) WHERE app_version IS NOT NULL DO UPDATE SET deployment_msg = $4",
|
||||
"query": "INSERT INTO deployment_metadata (workspace_id, path, app_version, deployment_msg) VALUES ($1, $2, $3, $4) ON CONFLICT (workspace_id, path, app_version) WHERE app_version IS NOT NULL DO UPDATE SET deployment_msg = EXCLUDED.deployment_msg",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -13,5 +13,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "652835b2b7f801532a591988ac76d385188991c6654d529f6d65f6f03794844a"
|
||||
"hash": "384753e7ceb602790646b0f269df48910d900b9575d986143823781e1d005d57"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"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) DO UPDATE SET value = $3, edited_at = now()",
|
||||
"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) DO UPDATE SET value = EXCLUDED.value, edited_at = now()",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -15,5 +15,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "42df4b40b3bbf14010f07e29892776992bfeb383d590e379244ad23703e536a4"
|
||||
"hash": "3904d59575e05df6e414be03e84ca7d07ee06d417a5bd9f02d64fcb467cf362a"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"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 = $3, description = $4, resource_type = $5, edited_at = now()",
|
||||
"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": {
|
||||
@@ -15,5 +15,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "c69719d0a63b0ca434c3317529e00e4d0df0104b6c1dbdf6d0f68f5047a2ad5e"
|
||||
"hash": "39426bd3018b390ea2073419884cf6cb506c75e84c65438c9026831eb10d340b"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO pip_resolution_cache (hash, lockfile, expiration) VALUES ($1, $2, now() + ('5 mins')::interval) ON CONFLICT (hash) DO UPDATE SET lockfile = $2",
|
||||
"query": "INSERT INTO pip_resolution_cache (hash, lockfile, expiration) VALUES ($1, $2, now() + ('5 mins')::interval) ON CONFLICT (hash) DO UPDATE SET lockfile = EXCLUDED.lockfile",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -11,5 +11,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "9a9e4a8779b0bf8a275d029221dfa1465e5d44cd8a7be5879219ffc8cd7ae6b1"
|
||||
"hash": "4d3b8726656ebf6eb78d0c4c23fdfa6325fcae4dc3bf559f2ecc683fb40537e8"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO job_logs (logs, job_id, workspace_id) VALUES ($1, $2, $3) ON CONFLICT (job_id) DO UPDATE SET logs = concat(job_logs.logs, $1::text)",
|
||||
"query": "INSERT INTO job_logs (logs, job_id, workspace_id) VALUES ($1, $2, $3) ON CONFLICT (job_id) DO UPDATE SET logs = concat(job_logs.logs, EXCLUDED.logs)",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -12,5 +12,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "c7dd35561e9b1cfd86238d410139f50e4d87c762e4867d8b32c11bd8c74846eb"
|
||||
"hash": "5585bc46fe2b9d5aebddad300f43b7cbc891e55d29d30d1ca7b13f25ed1fdc87"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO variable\n (workspace_id, path, value, is_secret, account, is_oauth, expires_at)\n VALUES ($1, $2, $3, $4, $5, $6, $7)\n ON CONFLICT (workspace_id, path) DO UPDATE SET value = $3, expires_at = $7",
|
||||
"query": "INSERT INTO variable\n (workspace_id, path, value, is_secret, account, is_oauth, expires_at)\n VALUES ($1, $2, $3, $4, $5, $6, $7)\n ON CONFLICT (workspace_id, path) DO UPDATE SET value = EXCLUDED.value, expires_at = EXCLUDED.expires_at",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -16,5 +16,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "08dd2ea6b17a52bce352d6443d7d009cfc9da0d3b2bd1f40d422b550779e5324"
|
||||
"hash": "5701ee0b862dbdb44990702af270a2eb517e82943bb8c078c7bb2e60def3cbf1"
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO instance_group (name, summary, id) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "59c63c5e3ce0b4976133cd65258ef6bfdecc81700b89962c758c065d8d55f9e2"
|
||||
}
|
||||
+2
-3
@@ -1,17 +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, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only, no_main_func, codebase, has_preprocessor, on_behalf_of_email, schema_validation, assets)\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, $4, 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, no_main_func, codebase, has_preprocessor, on_behalf_of_email, schema_validation, assets\n\n FROM script WHERE hash = $2 AND workspace_id = $3;\n ",
|
||||
"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, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only, no_main_func, codebase, has_preprocessor, on_behalf_of_email, schema_validation, assets)\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, dedicated_worker, ws_error_handler_muted, priority, restart_unless_cancelled, delete_after_use, timeout, concurrency_key, visible_to_runner_only, no_main_func, codebase, has_preprocessor, on_behalf_of_email, schema_validation, assets\n\n FROM script WHERE hash = $2 AND workspace_id = $3;\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8",
|
||||
"Int8",
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "b5fbd7893950610f1285662df24f438c9855ba860e23befd88c2544ef86e9133"
|
||||
"hash": "69550451b86f221a3d2ef626be7073fc77421710992b10f526aa36bc64ff0930"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO concurrency_locks (id, last_locked_at, owner)\n VALUES ($1, now(), $2)\n ON CONFLICT (id)\n DO UPDATE SET\n last_locked_at = now(),\n owner = $2",
|
||||
"query": "INSERT INTO concurrency_locks (id, last_locked_at, owner)\n VALUES ($1, now(), $2)\n ON CONFLICT (id)\n DO UPDATE SET\n last_locked_at = now(),\n owner = EXCLUDED.owner",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -11,5 +11,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "14abf759dae7ba5c38017ba6001927c6df0653a02b87bcea939066e39ebcf24d"
|
||||
"hash": "6d7a4185063dbcca0dbea1b002330d622c9d2d844a2ab3938e6ec23c6150fb40"
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT key FROM debounce_key WHERE job_id = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "key",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "73fcf81d272c1613e094d60c0a088f9d694bc37caacef7269e3738de8b5f6013"
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "DELETE FROM debounce_key WHERE key = $1",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "76774e6f72c8c8b7473487e4176dc17b17372b7292e39d3888a93ff4fe49e4f5"
|
||||
}
|
||||
+4
-4
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT versions[array_upper(versions, 1)] FROM flow WHERE path = $1 AND workspace_id = $2",
|
||||
"query": "SELECT id FROM flow_version WHERE path = $1 AND workspace_id = $2 ORDER BY created_at DESC LIMIT 1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "versions",
|
||||
"name": "id",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
@@ -16,8 +16,8 @@
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "526bfaccaafbe2e6f70dd5e6cd21c0c60d4ec155f79d067a8b74cf24eebad88c"
|
||||
"hash": "7bfb3b210d23f2c00a1d6a653e9df5d7df9acf74de6dcc566924de02f1807af2"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO workspace_invite\n (workspace_id, email, is_admin, operator)\n VALUES ($1, $2, $3, $4) ON CONFLICT (workspace_id, email)\n DO UPDATE SET is_admin = $3, operator = $4",
|
||||
"query": "INSERT INTO workspace_invite\n (workspace_id, email, is_admin, operator)\n VALUES ($1, $2, $3, $4) ON CONFLICT (workspace_id, email)\n DO UPDATE SET is_admin = EXCLUDED.is_admin, operator = EXCLUDED.operator",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -13,5 +13,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "d970a0b07a2b5840d1feb1baacb834dbaf91c633d3e7e1e29c8eb7eedc53e888"
|
||||
"hash": "7dc75cb67922e31ffe0f88b03a8a5bc14039aff6f023d79139b20519a9cdbe7d"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO workspace_settings\n (workspace_id, slack_team_id, slack_name, slack_email)\n VALUES ($1, $2, $3, $4) ON CONFLICT (workspace_id) DO UPDATE SET slack_team_id = $2, slack_name = $3, slack_email = $4",
|
||||
"query": "INSERT INTO workspace_settings\n (workspace_id, slack_team_id, slack_name, slack_email)\n VALUES ($1, $2, $3, $4) ON CONFLICT (workspace_id) DO UPDATE SET slack_team_id = EXCLUDED.slack_team_id, slack_name = EXCLUDED.slack_name, slack_email = EXCLUDED.slack_email",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -13,5 +13,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "43b376a2eff086a32cd76e54361ce3631feee1565935d2a6ddbecc17950758d1"
|
||||
"hash": "7dcc77eb6da5863f7a25ab6ad83d270e5e8a52540da1726aa875fcbe2517f16a"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO workspace_env (workspace_id, name, value) VALUES ($1, $2, $3) ON CONFLICT (workspace_id, name) DO UPDATE SET value = $3",
|
||||
"query": "INSERT INTO workspace_env (workspace_id, name, value) VALUES ($1, $2, $3) ON CONFLICT (workspace_id, name) DO UPDATE SET value = EXCLUDED.value",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -12,5 +12,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "b8c66d905a6c7ffa6441c84b14ea897040069dac7367895813cc2d64a9867193"
|
||||
"hash": "7dcf840fc5b329f4a591a51e24c9dacb12266f606b5ce7e8ed6110f3f381f945"
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO debounce_stale_data (job_id, to_relock)\n VALUES ($1, $2)\n ON CONFLICT (job_id)\n DO UPDATE SET to_relock = (\n SELECT array_agg(DISTINCT x)\n FROM unnest(\n -- Combine existing array with new values, removing duplicates\n array_cat(debounce_stale_data.to_relock, EXCLUDED.to_relock)\n ) AS x\n )\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"TextArray"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "7ec724b84479c2f737637e91b8cbed6cae29f361167deee879b8b683ad1bf684"
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO debounce_key (key, job_id) VALUES ($1, $2)",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Uuid"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "7ed404f3a8b23f98fb7c15a26b14f9e3e416e1baf20bdb25c9a8ac9efc288931"
|
||||
}
|
||||
-51
@@ -1,51 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO script (summary, description, dedicated_worker, content, workspace_id, path, hash, language, tag, created_by, lock) VALUES ('', '', true, $1, $2, $3, $4, $5, $6, $7, '') ON CONFLICT (workspace_id, hash) DO NOTHING",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Int8",
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Varchar",
|
||||
"Varchar"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "804fc11e35f4afc0db194b6fe2594f91df7e588d4d2431bc85f4d8734920c8bf"
|
||||
}
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO v2_job_queue (id, workspace_id, scheduled_for, tag) SELECT unnest($1::uuid[]), $2, now(), $3",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"UuidArray",
|
||||
"Varchar",
|
||||
"Varchar"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "85705fc3d7f8ba5f1b12d5fb222c38fc64deb1226aab9dc3bc4465324fce37d1"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "DELETE FROM _sqlx_migrations WHERE\n version=20250131115248 OR version=20250902085503 OR version=20250201145630 OR\n version=20250201145631 OR version=20250201145632",
|
||||
"query": "DELETE FROM _sqlx_migrations WHERE\n version=20250131115248 OR version=20250902085503 OR version=20250201145630 OR\n version=20250201145631 OR version=20250201145632 OR version=20251006143821",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -8,5 +8,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "618ec69c9c78f1c9e3539d2770392e3f783f29cd2cc58c0fc87d14ecef32b467"
|
||||
"hash": "8d4ad4ee75fb149c36a9f6a0c4cf5fd981473f45d1b71b4b8236e021f7c8682d"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO pip_resolution_cache (hash, lockfile, expiration) VALUES ($1, $2, now() + ('3 days')::interval) ON CONFLICT (hash) DO UPDATE SET lockfile = $2",
|
||||
"query": "INSERT INTO pip_resolution_cache (hash, lockfile, expiration) VALUES ($1, $2, now() + ('3 days')::interval) ON CONFLICT (hash) DO UPDATE SET lockfile = EXCLUDED.lockfile",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -11,5 +11,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "4fb3881cdbb4b9e93e28f460a9b3715bdc6a52b76c89f3a3913023b13c4e085c"
|
||||
"hash": "8fda0400ec5ba04a2a1469672bbb0af413027dbd39aa2c4182e3d219640d397e"
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT id FROM app_version WHERE app_id = (SELECT id FROM app WHERE path = $1 AND workspace_id = $2) ORDER BY created_at DESC LIMIT 1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "99e11c04bcc436ec7a75f46365423c85a6e6490c2d9e1dc6ac39112d763f0f75"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO tutorial_progress VALUES ($2, $1::bigint::bit(64)) ON CONFLICT (email) DO UPDATE SET progress = $1::bigint::bit(64)",
|
||||
"query": "INSERT INTO tutorial_progress VALUES ($2, $1::bigint::bit(64)) ON CONFLICT (email) DO UPDATE SET progress = EXCLUDED.progress",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -11,5 +11,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "e40f7e0b61567f948bfea0b6f50518564634885ccc2c0d30ccca79fc13bdcf07"
|
||||
"hash": "99e6bffe177e69448b09e82b30d24af00edc86a9bc498f319c1e5bee55d77a8a"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO usage (id, is_workspace, month_, usage) \n VALUES ($1, TRUE, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), $2) \n ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + $2",
|
||||
"query": "INSERT INTO usage (id, is_workspace, month_, usage) \n VALUES ($1, TRUE, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), $2) \n ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + EXCLUDED.usage",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -11,5 +11,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "f9e1334ecb17b313924587d96fc8b0310b14d75e85a558c8cb70f2761923d175"
|
||||
"hash": "9aebf706529889dc044e0ef41da8db2b1061c22698393c2e42d94da11e697b8b"
|
||||
}
|
||||
-15
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO v2_job_status (id, flow_status) SELECT unnest($1::uuid[]), $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"UuidArray",
|
||||
"Jsonb"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "a0b3e10e077d30c1da135dff9feca3761d400391f1f46a8294da3e6c9af63887"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO resource\n (workspace_id, path, value, resource_type, created_by, edited_at)\n VALUES ($1, $2, $3, $4, $5, now()) ON CONFLICT (workspace_id, path) DO UPDATE SET value = $3, edited_at = now()",
|
||||
"query": "INSERT INTO resource\n (workspace_id, path, value, resource_type, created_by, edited_at)\n VALUES ($1, $2, $3, $4, $5, now()) ON CONFLICT (workspace_id, path) DO UPDATE SET value = EXCLUDED.value, edited_at = now()",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -14,5 +14,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "20fcdcd2674a52ee9bd8d1de518d6bce075f20bcd5d2328f183d8a59331f6bb1"
|
||||
"hash": "a5bf005e0f7c9a86a136e049445de059481091ac173414418b8678f6beadf2ac"
|
||||
}
|
||||
-89
@@ -1,89 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO v2_job (id, runnable_id, runnable_path, kind, script_lang, tag, created_by, permissioned_as, permissioned_as_email, workspace_id, raw_flow) (SELECT gen_random_uuid(), $1, $2, $3, $4, $5, $6, $7, $8, $9, $10 FROM generate_series(1, 1)) RETURNING id",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id",
|
||||
"type_info": "Uuid"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8",
|
||||
"Varchar",
|
||||
{
|
||||
"Custom": {
|
||||
"name": "job_kind",
|
||||
"kind": {
|
||||
"Enum": [
|
||||
"script",
|
||||
"preview",
|
||||
"flow",
|
||||
"dependencies",
|
||||
"flowpreview",
|
||||
"script_hub",
|
||||
"identity",
|
||||
"flowdependencies",
|
||||
"http",
|
||||
"graphql",
|
||||
"postgresql",
|
||||
"noop",
|
||||
"appdependencies",
|
||||
"deploymentcallback",
|
||||
"singlestepflow",
|
||||
"flowscript",
|
||||
"flownode",
|
||||
"appscript",
|
||||
"aiagent"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Jsonb"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "ab04cda71f8e2be9acbecabe1ee5ef756b8e5c1955fbe111df9ee171dc262338"
|
||||
}
|
||||
+2
-2
@@ -18,8 +18,8 @@
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
true,
|
||||
false
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76"
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO draft\n (workspace_id, path, value, typ)\n VALUES ($1, $2, $3::text::json, $4)\n ON CONFLICT (workspace_id, path, typ) DO UPDATE SET value = $3::text::json",
|
||||
"query": "INSERT INTO draft\n (workspace_id, path, value, typ)\n VALUES ($1, $2, $3::text::json, $4)\n ON CONFLICT (workspace_id, path, typ) DO UPDATE SET value = EXCLUDED.value",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -24,5 +24,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "366609f7e7fbd73ea807128b931eff2f1ab763fa630c8531f590fed2110c03d9"
|
||||
"hash": "b474ae4401b3d4c95add2d3353eb66512801c20ad685e8ed544fe4b86601aaa8"
|
||||
}
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO v2_job_runtime (id) SELECT unnest($1::uuid[])",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"UuidArray"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "b4a9abcb38997587b28655b0f4a212a5bd4039b57fab20b163617e33a4c9dd46"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "WITH inserted_job AS (\n INSERT INTO v2_job (id, workspace_id, raw_code, raw_lock, raw_flow, tag, parent_job,\n created_by, permissioned_as, runnable_id, runnable_path, args, kind, trigger,\n script_lang, same_worker, pre_run_error, permissioned_as_email, visible_to_owner,\n flow_innermost_root_job, root_job, concurrent_limit, concurrency_time_window_s, timeout, flow_step_id,\n cache_ttl, priority, trigger_kind, script_entrypoint_override, preprocessed)\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 = $32, username = $33, is_admin = $34, is_operator = $35, folders = $36, groups = $37, workspace_id = $2\n )\n INSERT INTO v2_job_queue\n (workspace_id, id, running, scheduled_for, started_at, tag, priority)\n VALUES ($2, $1, $28, COALESCE($29, now()), CASE WHEN $27 OR $40 THEN now() END, $30, $31)",
|
||||
"query": "WITH inserted_job AS (\n INSERT INTO v2_job (id, workspace_id, raw_code, raw_lock, raw_flow, tag, parent_job,\n created_by, permissioned_as, runnable_id, runnable_path, args, kind, trigger,\n script_lang, same_worker, pre_run_error, permissioned_as_email, visible_to_owner,\n flow_innermost_root_job, root_job, concurrent_limit, concurrency_time_window_s, timeout, flow_step_id,\n cache_ttl, priority, trigger_kind, script_entrypoint_override, preprocessed)\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)\n VALUES ($2, $1, $28, COALESCE($29, now()), CASE WHEN $27 OR $40 THEN now() END, $30, $31)",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -129,5 +129,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "8d67ed8e1271a27b072a8e8ae9973e372949f5ec7d71b80d1ba3eaddf851adce"
|
||||
"hash": "bf2163c542fb8c4e173167a8f333ef762fecf782424c5b61b89f32918b8d6971"
|
||||
}
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO flow_version\n (workspace_id, path, value, schema, created_by)\n\n SELECT workspace_id, path, value, schema, created_by\n FROM flow_version WHERE path = $1 AND workspace_id = $2 AND id = $3\n\n RETURNING id",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text",
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "bf252ea52aeb57664ad5054b39998a5e50bc98a8360387bd4158f9bc1289319f"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\nWITH rows_to_delete AS (\n SELECT concurrency_id\n FROM concurrency_counter\n WHERE job_uuids = '{}'::jsonb\n FOR UPDATE SKIP LOCKED\n)\nDELETE FROM concurrency_counter\nWHERE concurrency_id IN (SELECT concurrency_id FROM rows_to_delete) RETURNING concurrency_id",
|
||||
"query": "\nWITH rows_to_delete AS (\n SELECT concurrency_id\n FROM concurrency_counter\n \n WHERE job_uuids = '{}'::jsonb\n FOR UPDATE SKIP LOCKED\n)\nDELETE FROM concurrency_counter\nWHERE concurrency_id IN (SELECT concurrency_id FROM rows_to_delete) RETURNING concurrency_id",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -16,5 +16,5 @@
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "9f4811fe735d401b62f4b7bf3db2b5cd13eb3364a8a8546007dec7ab528b1f9d"
|
||||
"hash": "c6ef0acdf20bd71dd26de981fb49f178ba8a1b8c1e01e0fec1dfd6a54ea7a894"
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT versions[array_upper(versions, 1)] FROM app WHERE path = $1 AND workspace_id = $2",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "versions",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "ca15fe5d43f0e94f50408efe5c9e359770b759e8661687b4503c4b692ecd245e"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO deployment_metadata (workspace_id, path, flow_version, deployment_msg) VALUES ($1, $2, $3, $4) ON CONFLICT (workspace_id, path, flow_version) WHERE flow_version IS NOT NULL DO UPDATE SET deployment_msg = $4",
|
||||
"query": "INSERT INTO deployment_metadata (workspace_id, path, flow_version, deployment_msg) VALUES ($1, $2, $3, $4) ON CONFLICT (workspace_id, path, flow_version) WHERE flow_version IS NOT NULL DO UPDATE SET deployment_msg = EXCLUDED.deployment_msg",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -13,5 +13,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "afc7c23c057748f6d4a61dbef17e433b8875c6588b91e38e8141d12189118412"
|
||||
"hash": "cc8e10a4f39e118b145cc8f6fbd5f3db1fb30c9564ed039ad4c952333ec29b39"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO usage (id, is_workspace, month_, usage) \n VALUES ($1, FALSE, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), $2) \n ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + $2",
|
||||
"query": "INSERT INTO usage (id, is_workspace, month_, usage) \n VALUES ($1, FALSE, EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date), $2) \n ON CONFLICT (id, is_workspace, month_) DO UPDATE SET usage = usage.usage + EXCLUDED.usage",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -11,5 +11,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "7b48820a08fbb3bee0fb2dc802a0b4f28ed5507797165e8c577ce6a95d11694c"
|
||||
"hash": "ceb10ca124d9425b24d81d8a279a13481db39eea0b52cc513b3ee6571cf44ed4"
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "DELETE FROM debounce_stale_data WHERE job_id = $1 RETURNING to_relock",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "to_relock",
|
||||
"type_info": "TextArray"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "cfe06702916362aaf5122bb95593eff389e0d44b7a58b69fd5c79629599902fc"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n INSERT INTO job_result_stream_v2 (workspace_id, job_id, stream, idx)\n VALUES (\n $1, \n $2,\n $3, \n $4\n )\n ON CONFLICT (job_id, idx) DO UPDATE SET stream = job_result_stream_v2.stream || $3\n ",
|
||||
"query": "\n INSERT INTO job_result_stream_v2 (workspace_id, job_id, stream, idx)\n VALUES (\n $1, \n $2,\n $3, \n $4\n )\n ON CONFLICT (job_id, idx) DO UPDATE SET stream = job_result_stream_v2.stream || EXCLUDED.stream\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -13,5 +13,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "9bfc2a821b25641af48b0e3954163078922340294f1c6515400fb2c896666fde"
|
||||
"hash": "d142ff8b56f4b69c20815230b5b763ce8ce9fbe89abe83989f52ff3657690fef"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT hash FROM script WHERE path = $1 AND workspace_id = $2",
|
||||
"query": "SELECT hash FROM script WHERE path = $1 AND workspace_id = $2 AND deleted = false ORDER BY created_at DESC LIMIT 1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -19,5 +19,5 @@
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "16e4b1bead9fc77fd98658b8cb8cc6d6bf1df758b30e99bd661da866062ef14f"
|
||||
"hash": "d5661c7557cf3a8dee7cf799cd364d21d38edb827d2c08b0ca7d72311b78d574"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO global_settings (name, value) VALUES ('slack', $1) ON CONFLICT (name) DO UPDATE SET value = $1, updated_at = now()",
|
||||
"query": "INSERT INTO global_settings (name, value) VALUES ('slack', $1) ON CONFLICT (name) DO UPDATE SET value = EXCLUDED.value, updated_at = now()",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -10,5 +10,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "fb581eb6f883ebb5909a00c65a6e1217f088290fce0e052171230bcd88f945b9"
|
||||
"hash": "da7e23a32f284c9760614735d459474d2f8513202dfb64767b30e7b50833b857"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO cloud_workspace_settings (workspace_id, threshold_alert_amount) VALUES ($1, $2) ON CONFLICT (workspace_id) DO UPDATE SET threshold_alert_amount = $2, last_alert_sent = NULL",
|
||||
"query": "INSERT INTO cloud_workspace_settings (workspace_id, threshold_alert_amount) VALUES ($1, $2) ON CONFLICT (workspace_id) DO UPDATE SET threshold_alert_amount = EXCLUDED.threshold_alert_amount, last_alert_sent = NULL",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -11,5 +11,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "c4e0f3eab227a798d9cd7478db50a7c1a588e69c2c8d9a1def9276ba326453d2"
|
||||
"hash": "db201730803047bfabccf5f10456243b590b2dd0cfe41aa5100a7e829afad9d3"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO job_logs (logs, job_id, workspace_id) VALUES ($1, $2, $3) ON CONFLICT (job_id) DO UPDATE SET logs = concat(job_logs.logs, $1::text) RETURNING length(logs)",
|
||||
"query": "INSERT INTO job_logs (logs, job_id, workspace_id) VALUES ($1, $2, $3) ON CONFLICT (job_id) DO UPDATE SET logs = concat(job_logs.logs, EXCLUDED.logs) RETURNING length(logs)",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -20,5 +20,5 @@
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "a2e86f169ffbf8acee5f7c7b71db5859ac94ffbad267c9cd6c652e8ce8fc5d3c"
|
||||
"hash": "e16f464c7e302e80f1017ff6550716448202c1181ca0b36936a9c8840c14a95d"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO deployment_metadata (workspace_id, path, app_version, callback_job_ids, deployment_msg) VALUES ($1, $2, $3, $4, $5)\n ON CONFLICT (workspace_id, path, app_version) WHERE app_version IS NOT NULL DO UPDATE SET callback_job_ids = $4, deployment_msg = $5",
|
||||
"query": "INSERT INTO deployment_metadata (workspace_id, path, app_version, callback_job_ids, deployment_msg) VALUES ($1, $2, $3, $4, $5)\n ON CONFLICT (workspace_id, path, app_version) WHERE app_version IS NOT NULL DO UPDATE SET callback_job_ids = EXCLUDED.callback_job_ids, deployment_msg = EXCLUDED.deployment_msg",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -14,5 +14,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "f37140fcdc721a8b199471b30c2baf124affa2eaf56c801c8dac3264c584f981"
|
||||
"hash": "e572fa64eec9188368d7c271ac7ecd6b45dc161423abab22cddb2b13f6fb9833"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO worker_ping (worker_instance, worker, ip, custom_tags, worker_group, dedicated_worker, wm_version, vcpus, memory) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) ON CONFLICT (worker) DO UPDATE set ip = $3, custom_tags = $4, worker_group = $5",
|
||||
"query": "INSERT INTO worker_ping (worker_instance, worker, ip, custom_tags, worker_group, dedicated_worker, wm_version, vcpus, memory) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) ON CONFLICT (worker) \n DO UPDATE set ip = EXCLUDED.ip, custom_tags = EXCLUDED.custom_tags, worker_group = EXCLUDED.worker_group",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -18,5 +18,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "6afc5c7cbb3abe11ade0cedf1f7328005ce4de3165cdd998e5a0d27e044c7153"
|
||||
"hash": "e5f8830450e90f678494ae2b0f86b0692a02dec4c8415fd7d364b0cc088905c2"
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO deployment_metadata (workspace_id, path, flow_version, callback_job_ids, deployment_msg) VALUES ($1, $2, $3, $4, $5)\n ON CONFLICT (workspace_id, path, flow_version) WHERE flow_version IS NOT NULL DO UPDATE SET callback_job_ids = $4, deployment_msg = $5",
|
||||
"query": "INSERT INTO deployment_metadata (workspace_id, path, flow_version, callback_job_ids, deployment_msg) VALUES ($1, $2, $3, $4, $5)\n ON CONFLICT (workspace_id, path, flow_version) WHERE flow_version IS NOT NULL DO UPDATE SET callback_job_ids = EXCLUDED.callback_job_ids, deployment_msg = EXCLUDED.deployment_msg",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -14,5 +14,5 @@
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "2367e7c0f7fbafe0971a187c0909617da55251e97180babf6ac9e8068f26d73d"
|
||||
"hash": "e8e33f599eae064011232f9f715e676d0c8ae31982865cb2c8103ed735c42c69"
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO flow_version\n (workspace_id, path, value, schema, created_by)\n\n SELECT workspace_id, path, value, schema, created_by\n FROM flow_version WHERE path = $1 AND workspace_id = $2 AND id = $3\n\n RETURNING id\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text",
|
||||
"Int8"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "f0efa383f2025158de160577ad839ae72faf0c8fe097e6ad6d309aee9a8aede2"
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT job_id FROM debounce_key WHERE key = $1 FOR UPDATE",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "job_id",
|
||||
"type_info": "Uuid"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "fe1539db7384c8edc6d8ec672495fe3964efb8551ad6d74f141fc457034cc5b9"
|
||||
}
|
||||
-89
@@ -1,89 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO v2_job (id, runnable_id, runnable_path, kind, script_lang, tag, created_by, permissioned_as, permissioned_as_email, workspace_id) (SELECT gen_random_uuid(), $1, $2, $3, $4, $5, $6, $7, $8, $9 FROM generate_series(1, $10)) RETURNING id",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id",
|
||||
"type_info": "Uuid"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Int8",
|
||||
"Varchar",
|
||||
{
|
||||
"Custom": {
|
||||
"name": "job_kind",
|
||||
"kind": {
|
||||
"Enum": [
|
||||
"script",
|
||||
"preview",
|
||||
"flow",
|
||||
"dependencies",
|
||||
"flowpreview",
|
||||
"script_hub",
|
||||
"identity",
|
||||
"flowdependencies",
|
||||
"http",
|
||||
"graphql",
|
||||
"postgresql",
|
||||
"noop",
|
||||
"appdependencies",
|
||||
"deploymentcallback",
|
||||
"singlestepflow",
|
||||
"flowscript",
|
||||
"flownode",
|
||||
"appscript",
|
||||
"aiagent"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Int4"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "ff0403790674cdb07022af71c2377afbd8b3a660b3be27514b517c077c63c238"
|
||||
}
|
||||
Generated
+67
-75
@@ -122,7 +122,7 @@ checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"const-random",
|
||||
"getrandom 0.3.3",
|
||||
"getrandom 0.3.4",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
"zerocopy",
|
||||
@@ -791,9 +791,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-lc-rs"
|
||||
version = "1.14.0"
|
||||
version = "1.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94b8ff6c09cd57b16da53641caa860168b88c172a5ee163b0288d3d6eea12786"
|
||||
checksum = "879b6c89592deb404ba4dc0ae6b58ffd1795c78991cbb5b8bc441c48a070440d"
|
||||
dependencies = [
|
||||
"aws-lc-sys",
|
||||
"zeroize",
|
||||
@@ -801,9 +801,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "aws-lc-sys"
|
||||
version = "0.31.0"
|
||||
version = "0.32.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0e44d16778acaf6a9ec9899b92cebd65580b83f685446bf2e1f5d3d732f99dcd"
|
||||
checksum = "107a4e9d9cab9963e04e84bb8dee0e25f2a987f9a8bad5ed054abd439caa8f8c"
|
||||
dependencies = [
|
||||
"bindgen 0.72.1",
|
||||
"cc",
|
||||
@@ -1023,7 +1023,7 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
"rustls 0.21.12",
|
||||
"rustls 0.23.29",
|
||||
"rustls-native-certs 0.8.1",
|
||||
"rustls-native-certs 0.8.2",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tower 0.5.2",
|
||||
@@ -1962,9 +1962,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9"
|
||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "cfg_aliases"
|
||||
@@ -4831,9 +4831,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dyn-stack-macros"
|
||||
version = "0.1.0"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05dbec7076f432bb132db738df90d87a4f5789e99f59e7b1219a6b8ef61eaa68"
|
||||
checksum = "e1d926b4d407d372f141f93bb444696142c29d32962ccbd3531117cf3aa0bfa9"
|
||||
|
||||
[[package]]
|
||||
name = "dynasm"
|
||||
@@ -5870,21 +5870,21 @@ dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi 0.11.1+wasi-snapshot-preview1",
|
||||
"wasi",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.3.3"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
|
||||
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasi 0.14.7+wasi-0.2.4",
|
||||
"wasip2",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
@@ -5943,9 +5943,9 @@ checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
|
||||
|
||||
[[package]]
|
||||
name = "globset"
|
||||
version = "0.4.16"
|
||||
version = "0.4.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5"
|
||||
checksum = "eab69130804d941f8075cfd713bf8848a2c3b3f201a9457a11e6f87e1ab62305"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"bstr",
|
||||
@@ -6666,7 +6666,7 @@ dependencies = [
|
||||
"hyper-util",
|
||||
"log",
|
||||
"rustls 0.23.29",
|
||||
"rustls-native-certs 0.8.1",
|
||||
"rustls-native-certs 0.8.2",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tokio-rustls 0.26.4",
|
||||
@@ -6911,9 +6911,9 @@ checksum = "cd62e6b5e86ea8eeeb8db1de02880a6abc01a397b2ebb64b5d74ac255318f5cb"
|
||||
|
||||
[[package]]
|
||||
name = "ignore"
|
||||
version = "0.4.23"
|
||||
version = "0.4.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b"
|
||||
checksum = "81776e6f9464432afcc28d03e52eb101c93b6f0566f52aef2427663e700f0403"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"globset",
|
||||
@@ -7182,7 +7182,7 @@ version = "0.1.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33"
|
||||
dependencies = [
|
||||
"getrandom 0.3.3",
|
||||
"getrandom 0.3.4",
|
||||
"libc",
|
||||
]
|
||||
|
||||
@@ -8180,7 +8180,7 @@ checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi 0.11.1+wasi-snapshot-preview1",
|
||||
"wasi",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
@@ -8191,7 +8191,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.11.1+wasi-snapshot-preview1",
|
||||
"wasi",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
@@ -8330,7 +8330,7 @@ dependencies = [
|
||||
"bytes",
|
||||
"crc32fast",
|
||||
"flate2",
|
||||
"getrandom 0.3.3",
|
||||
"getrandom 0.3.4",
|
||||
"mysql-common-derive",
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
@@ -9058,9 +9058,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.73"
|
||||
version = "0.10.74"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8"
|
||||
checksum = "24ad14dd45412269e1a30f52ad8f0664f0f4f4a89ee8fe28c3b3527021ebb654"
|
||||
dependencies = [
|
||||
"bitflags 2.9.4",
|
||||
"cfg-if",
|
||||
@@ -9099,9 +9099,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.109"
|
||||
version = "0.9.110"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571"
|
||||
checksum = "0a9f0075ba3c21b09f8e8b2026584b1d18d49388648f2fbbf3c97ea8deced8e2"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
@@ -10179,9 +10179,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pure-rust-locales"
|
||||
version = "0.8.1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1190fd18ae6ce9e137184f207593877e70f39b015040156b1e05081cdfe3733a"
|
||||
checksum = "869675ad2d7541aea90c6d88c81f46a7f4ea9af8cd0395d38f11a95126998a0d"
|
||||
|
||||
[[package]]
|
||||
name = "pwd"
|
||||
@@ -10252,7 +10252,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"getrandom 0.3.3",
|
||||
"getrandom 0.3.4",
|
||||
"lru-slab",
|
||||
"rand 0.9.0",
|
||||
"ring 0.17.14",
|
||||
@@ -10368,7 +10368,7 @@ version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38"
|
||||
dependencies = [
|
||||
"getrandom 0.3.3",
|
||||
"getrandom 0.3.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -10700,7 +10700,7 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
"quinn",
|
||||
"rustls 0.23.29",
|
||||
"rustls-native-certs 0.8.1",
|
||||
"rustls-native-certs 0.8.2",
|
||||
"rustls-pki-types",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -11161,9 +11161,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "rustls-native-certs"
|
||||
version = "0.8.1"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3"
|
||||
checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923"
|
||||
dependencies = [
|
||||
"openssl-probe",
|
||||
"rustls-pki-types",
|
||||
@@ -13305,7 +13305,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"getrandom 0.3.3",
|
||||
"getrandom 0.3.4",
|
||||
"once_cell",
|
||||
"rustix 1.1.2",
|
||||
"windows-sys 0.61.2",
|
||||
@@ -13832,7 +13832,7 @@ dependencies = [
|
||||
"httparse",
|
||||
"rand 0.8.5",
|
||||
"ring 0.17.14",
|
||||
"rustls-native-certs 0.8.1",
|
||||
"rustls-native-certs 0.8.2",
|
||||
"rustls-pki-types",
|
||||
"tokio",
|
||||
"tokio-rustls 0.26.4",
|
||||
@@ -13925,7 +13925,7 @@ dependencies = [
|
||||
"percent-encoding",
|
||||
"pin-project",
|
||||
"prost",
|
||||
"rustls-native-certs 0.8.1",
|
||||
"rustls-native-certs 0.8.2",
|
||||
"rustls-pemfile 2.2.0",
|
||||
"socket2 0.5.10",
|
||||
"tokio",
|
||||
@@ -14652,7 +14652,7 @@ version = "1.18.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2"
|
||||
dependencies = [
|
||||
"getrandom 0.3.3",
|
||||
"getrandom 0.3.4",
|
||||
"js-sys",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
@@ -14760,15 +14760,6 @@ version = "0.11.1+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.14.7+wasi-0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "883478de20367e224c0090af9cf5f9fa85bed63a95c1abf3afc5c083ebc06e8c"
|
||||
dependencies = [
|
||||
"wasip2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasip2"
|
||||
version = "1.0.1+wasi-0.2.4"
|
||||
@@ -15131,7 +15122,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windmill"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"aws-sdk-config",
|
||||
@@ -15191,7 +15182,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argon2",
|
||||
@@ -15311,7 +15302,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-api-client"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
@@ -15326,7 +15317,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-audit"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"serde",
|
||||
@@ -15339,7 +15330,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-autoscaling"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
@@ -15358,7 +15349,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-common"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
@@ -15442,7 +15433,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-git-sync"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"regex",
|
||||
"serde",
|
||||
@@ -15457,7 +15448,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-indexer"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
@@ -15481,7 +15472,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-macros"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"itertools 0.14.0",
|
||||
"lazy_static",
|
||||
@@ -15493,7 +15484,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"convert_case 0.6.0",
|
||||
"serde",
|
||||
@@ -15502,7 +15493,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-bash"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -15514,7 +15505,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-csharp"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"serde_json",
|
||||
@@ -15526,7 +15517,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-go"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"gosyn",
|
||||
@@ -15538,7 +15529,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-graphql"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -15550,7 +15541,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-java"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"serde_json",
|
||||
@@ -15562,7 +15553,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-nu"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"nu-parser",
|
||||
@@ -15573,7 +15564,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-php"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.14.0",
|
||||
@@ -15584,7 +15575,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-py"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"itertools 0.14.0",
|
||||
@@ -15596,7 +15587,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-py-imports"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
@@ -15619,7 +15610,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-ruby"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -15633,7 +15624,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-rust"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"convert_case 0.6.0",
|
||||
@@ -15650,7 +15641,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-sql"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -15664,7 +15655,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-ts"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"lazy_static",
|
||||
@@ -15682,7 +15673,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-wasm"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"getrandom 0.2.16",
|
||||
@@ -15707,9 +15698,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-parser-yaml"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"windmill-parser",
|
||||
"yaml-rust",
|
||||
@@ -15717,7 +15709,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-queue"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-recursion",
|
||||
@@ -15750,7 +15742,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-sql-datatype-parser-wasm"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-test",
|
||||
@@ -15760,7 +15752,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windmill-worker"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-once-cell",
|
||||
|
||||
+3
-2
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "windmill"
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
@@ -34,7 +34,7 @@ members = [
|
||||
exclude = ["./windmill-duckdb-ffi-internal"]
|
||||
|
||||
[workspace.package]
|
||||
version = "1.559.0"
|
||||
version = "1.562.0"
|
||||
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
|
||||
edition = "2021"
|
||||
|
||||
@@ -86,6 +86,7 @@ oauth2 = ["windmill-api/oauth2"]
|
||||
zip = ["windmill-api/zip"]
|
||||
static_frontend = ["windmill-api/static_frontend"]
|
||||
scoped_cache = ["windmill-common/scoped_cache"]
|
||||
test_job_debouncing = []
|
||||
# Languages
|
||||
python = ["windmill-worker/python", "windmill-api/python"]
|
||||
rust = ["windmill-worker/rust"]
|
||||
|
||||
@@ -1 +1 @@
|
||||
19909371503adfa12106dbf261d7f4134989a204
|
||||
365a3c9dd7a3fddc3280bbda86ba93ef149d1b64
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
DROP TABLE IF EXISTS debounce_key;
|
||||
DROP TABLE IF EXISTS debounce_stale_data;
|
||||
DROP TABLE IF EXISTS debounce_obj_latest_version;
|
||||
@@ -0,0 +1,19 @@
|
||||
CREATE TABLE debounce_key (
|
||||
key VARCHAR(255) NOT NULL,
|
||||
job_id uuid NOT NULL,
|
||||
PRIMARY KEY (key)
|
||||
);
|
||||
|
||||
CREATE TABLE debounce_stale_data (
|
||||
job_id uuid NOT NULL,
|
||||
to_relock TEXT[],
|
||||
PRIMARY KEY (job_id)
|
||||
);
|
||||
|
||||
-- TODO: Prune on move/deletion
|
||||
-- But normally this will persist across runs.
|
||||
-- CREATE TABLE unlocked_script_latest_version (
|
||||
-- key VARCHAR(255) NOT NULL,
|
||||
-- version BIGINT NOT NULL,
|
||||
-- PRIMARY KEY (key)
|
||||
-- );
|
||||
@@ -0,0 +1 @@
|
||||
-- Add down migration script here
|
||||
@@ -0,0 +1,37 @@
|
||||
|
||||
-- Users of instance_settings.yaml would have issues where it deletes ducklake_user_pg_pwd
|
||||
-- and then the next migration fails because it tries to insert a NULL value
|
||||
|
||||
-- When everything is fine (i.e ducklake_user_pg_pwd or ducklake_settings is present)
|
||||
-- this should be a no-op
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
new_settings_value text;
|
||||
old_setting_value text;
|
||||
BEGIN
|
||||
SELECT value INTO new_settings_value FROM global_settings WHERE name = 'ducklake_settings';
|
||||
SELECT trim(both '"' from value::text) INTO old_setting_value FROM global_settings WHERE name = 'ducklake_user_pg_pwd';
|
||||
|
||||
IF new_settings_value IS NULL AND old_setting_value IS NULL THEN
|
||||
-- Copied from 20250731132157_ducklake_instance_settings.up.sql
|
||||
|
||||
INSERT INTO global_settings (name, value)
|
||||
VALUES ('ducklake_user_pg_pwd', ('"' || gen_random_uuid()::text || '"')::jsonb)
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- Cannot simply create the user because Postgres expect a static string for the password
|
||||
-- Also we cannot drop the user easily in the down migration because databases will depend on it
|
||||
-- And we cannot drop databases in transactions (migrations)
|
||||
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'ducklake_user') THEN
|
||||
EXECUTE format('CREATE USER ducklake_user WITH PASSWORD %L', old_setting_value);
|
||||
ELSE
|
||||
EXECUTE format('ALTER USER ducklake_user WITH PASSWORD %L', old_setting_value);
|
||||
END IF;
|
||||
END IF;
|
||||
EXCEPTION
|
||||
WHEN others THEN
|
||||
RAISE NOTICE 'ducklake_user migration error, skipping.';
|
||||
END
|
||||
$$;
|
||||
@@ -0,0 +1,4 @@
|
||||
-- Add down migration script here
|
||||
|
||||
-- This migration is irreversible as we cannot safely remove UUIDs
|
||||
-- that may already be in use by SCIM clients
|
||||
@@ -0,0 +1,7 @@
|
||||
-- Add up migration script here
|
||||
|
||||
-- Backfill UUIDs for instance groups that don't have one
|
||||
-- This is needed for SCIM compatibility where groups must have stable UUIDs
|
||||
UPDATE instance_group
|
||||
SET id = gen_random_uuid()::text
|
||||
WHERE id IS NULL;
|
||||
+19
-48
@@ -2,47 +2,32 @@
|
||||
"github": {
|
||||
"auth_url": "https://github.com/login/oauth/authorize",
|
||||
"token_url": "https://github.com/login/oauth/access_token",
|
||||
"scopes": [
|
||||
"workflow",
|
||||
"repo"
|
||||
]
|
||||
"scopes": ["workflow", "repo"]
|
||||
},
|
||||
"gitlab": {
|
||||
"auth_url": "https://gitlab.com/oauth/authorize",
|
||||
"token_url": "https://gitlab.com/oauth/token",
|
||||
"scopes": [
|
||||
"api"
|
||||
]
|
||||
"scopes": ["api"]
|
||||
},
|
||||
"bitbucket": {
|
||||
"auth_url": "https://bitbucket.org/site/oauth2/authorize",
|
||||
"token_url": "https://bitbucket.org/site/oauth2/access_token",
|
||||
"scopes": [
|
||||
"repository"
|
||||
]
|
||||
"scopes": ["repository"]
|
||||
},
|
||||
"slack": {
|
||||
"auth_url": "https://slack.com/oauth/authorize",
|
||||
"token_url": "https://slack.com/api/oauth.access",
|
||||
"scopes": [
|
||||
"chat:write:user",
|
||||
"users:read",
|
||||
"users:read.email"
|
||||
]
|
||||
"scopes": ["chat:write:user", "users:read", "users:read.email"]
|
||||
},
|
||||
"supabase_wizard": {
|
||||
"auth_url": "https://api.supabase.com/v1/oauth/authorize",
|
||||
"token_url": "https://api.supabase.com/v1/oauth/token",
|
||||
"scopes": [
|
||||
"all"
|
||||
]
|
||||
"scopes": ["all"]
|
||||
},
|
||||
"gsheets": {
|
||||
"auth_url": "https://accounts.google.com/o/oauth2/v2/auth",
|
||||
"token_url": "https://oauth2.googleapis.com/token",
|
||||
"scopes": [
|
||||
"https://www.googleapis.com/auth/spreadsheets"
|
||||
],
|
||||
"scopes": ["https://www.googleapis.com/auth/spreadsheets"],
|
||||
"extra_params": {
|
||||
"access_type": "offline",
|
||||
"prompt": "consent"
|
||||
@@ -51,9 +36,7 @@
|
||||
"gdrive": {
|
||||
"auth_url": "https://accounts.google.com/o/oauth2/v2/auth",
|
||||
"token_url": "https://oauth2.googleapis.com/token",
|
||||
"scopes": [
|
||||
"https://www.googleapis.com/auth/drive"
|
||||
],
|
||||
"scopes": ["https://www.googleapis.com/auth/drive"],
|
||||
"extra_params": {
|
||||
"access_type": "offline",
|
||||
"prompt": "consent"
|
||||
@@ -62,9 +45,7 @@
|
||||
"gmail": {
|
||||
"auth_url": "https://accounts.google.com/o/oauth2/v2/auth",
|
||||
"token_url": "https://oauth2.googleapis.com/token",
|
||||
"scopes": [
|
||||
"https://www.googleapis.com/auth/gmail.send"
|
||||
],
|
||||
"scopes": ["https://www.googleapis.com/auth/gmail.send"],
|
||||
"extra_params": {
|
||||
"access_type": "offline",
|
||||
"prompt": "consent"
|
||||
@@ -73,9 +54,7 @@
|
||||
"gcal": {
|
||||
"auth_url": "https://accounts.google.com/o/oauth2/v2/auth",
|
||||
"token_url": "https://oauth2.googleapis.com/token",
|
||||
"scopes": [
|
||||
"https://www.googleapis.com/auth/calendar.events"
|
||||
],
|
||||
"scopes": ["https://www.googleapis.com/auth/calendar.events"],
|
||||
"extra_params": {
|
||||
"access_type": "offline",
|
||||
"prompt": "consent"
|
||||
@@ -84,9 +63,7 @@
|
||||
"gforms": {
|
||||
"auth_url": "https://accounts.google.com/o/oauth2/v2/auth",
|
||||
"token_url": "https://oauth2.googleapis.com/token",
|
||||
"scopes": [
|
||||
"https://www.googleapis.com/auth/forms"
|
||||
],
|
||||
"scopes": ["https://www.googleapis.com/auth/forms"],
|
||||
"extra_params": {
|
||||
"access_type": "offline",
|
||||
"prompt": "consent"
|
||||
@@ -95,9 +72,7 @@
|
||||
"gcloud": {
|
||||
"auth_url": "https://accounts.google.com/o/oauth2/v2/auth",
|
||||
"token_url": "https://oauth2.googleapis.com/token",
|
||||
"scopes": [
|
||||
"https://www.googleapis.com/auth/cloud-platform"
|
||||
],
|
||||
"scopes": ["https://www.googleapis.com/auth/cloud-platform"],
|
||||
"extra_params": {
|
||||
"access_type": "offline",
|
||||
"prompt": "consent"
|
||||
@@ -128,19 +103,13 @@
|
||||
"linkedin": {
|
||||
"auth_url": "https://www.linkedin.com/oauth/v2/authorization",
|
||||
"token_url": "https://www.linkedin.com/oauth/v2/accessToken",
|
||||
"scopes": [
|
||||
"w_member_social",
|
||||
"r_liteprofile",
|
||||
"r_emailaddress"
|
||||
],
|
||||
"scopes": ["w_member_social", "r_liteprofile", "r_emailaddress"],
|
||||
"req_body_auth": true
|
||||
},
|
||||
"quickbooks": {
|
||||
"auth_url": "https://appcenter.intuit.com/connect/oauth2",
|
||||
"token_url": "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer",
|
||||
"scopes": [
|
||||
"com.intuit.quickbooks.accounting"
|
||||
]
|
||||
"scopes": ["com.intuit.quickbooks.accounting"]
|
||||
},
|
||||
"visma": {
|
||||
"auth_url": "https://connect.visma.com/connect/authorize",
|
||||
@@ -153,6 +122,11 @@
|
||||
"vismanet_erp_interactive_api:update"
|
||||
]
|
||||
},
|
||||
"sage_intacct": {
|
||||
"auth_url": "https://api.intacct.com/ia/api/v1/oauth2/authorize",
|
||||
"token_url": "https://api.intacct.com/ia/api/v1/oauth2/token",
|
||||
"scopes": ["offline_access"]
|
||||
},
|
||||
"spotify": {
|
||||
"auth_url": "https://accounts.spotify.com/authorize",
|
||||
"token_url": "https://accounts.spotify.com/api/token",
|
||||
@@ -175,10 +149,7 @@
|
||||
"xero": {
|
||||
"auth_url": "https://login.xero.com/identity/connect/authorize",
|
||||
"token_url": "https://identity.xero.com/connect/token",
|
||||
"scopes": [
|
||||
"offline_access",
|
||||
"accounting.transactions"
|
||||
]
|
||||
"scopes": ["offline_access", "accounting.transactions"]
|
||||
},
|
||||
"zoho": {
|
||||
"auth_url": "https://accounts.zoho.com/oauth/v2/auth",
|
||||
|
||||
@@ -150,6 +150,16 @@ pub fn parse_ansible(code: &str) -> String {
|
||||
wrap_sig(windmill_parser_yaml::parse_ansible_sig(code))
|
||||
}
|
||||
|
||||
#[cfg(feature = "ansible-parser")]
|
||||
#[wasm_bindgen]
|
||||
pub fn parse_ansible_delegate(code: &str) -> String {
|
||||
if let Ok(r) = windmill_parser_yaml::parse_delegate_to_git_repo(code) {
|
||||
return serde_json::to_string(&r).unwrap();
|
||||
} else {
|
||||
return "Invalid".to_string();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "csharp-parser")]
|
||||
#[wasm_bindgen]
|
||||
pub fn parse_csharp(code: &str) -> String {
|
||||
@@ -173,6 +183,7 @@ pub fn parse_java(code: &str) -> String {
|
||||
pub fn parse_ruby(code: &str) -> String {
|
||||
wrap_sig(windmill_parser_ruby::parse_ruby_signature(code))
|
||||
}
|
||||
|
||||
#[cfg(feature = "sql-parser")]
|
||||
#[wasm_bindgen]
|
||||
pub fn parse_assets_sql(code: &str) -> String {
|
||||
@@ -203,4 +214,15 @@ pub fn parse_assets_py(code: &str) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ansible-parser")]
|
||||
#[wasm_bindgen]
|
||||
pub fn parse_assets_ansible(code: &str) -> String {
|
||||
let o = windmill_parser_yaml::parse_assets(code);
|
||||
if let Ok(r) = o {
|
||||
return serde_json::to_string(&r).unwrap();
|
||||
} else {
|
||||
return format!("err: {:?}", o.err().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
// for related places search: ADD_NEW_LANG
|
||||
|
||||
@@ -13,3 +13,4 @@ yaml-rust.workspace = true
|
||||
windmill-parser.workspace = true
|
||||
anyhow.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde.workspace = true
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
use windmill_parser::asset_parser::{
|
||||
merge_assets, AssetKind, AssetUsageAccessType, ParseAssetsResult,
|
||||
};
|
||||
|
||||
use crate::{parse_ansible_reqs, ResourceOrVariablePath};
|
||||
|
||||
pub fn parse_assets(input: &str) -> anyhow::Result<Vec<ParseAssetsResult<String>>> {
|
||||
let mut assets = vec![];
|
||||
if let (_, Some(ansible_reqs), _) = parse_ansible_reqs(input)? {
|
||||
if let Some(delegate_to_git_repo_details) = ansible_reqs.delegate_to_git_repo {
|
||||
assets.push(ParseAssetsResult {
|
||||
kind: AssetKind::Resource,
|
||||
path: delegate_to_git_repo_details.resource,
|
||||
access_type: Some(AssetUsageAccessType::R),
|
||||
})
|
||||
}
|
||||
|
||||
for i in ansible_reqs.inventories {
|
||||
if let Some(pinned_res) = i.pinned_resource {
|
||||
assets.push(ParseAssetsResult {
|
||||
kind: AssetKind::Resource,
|
||||
path: pinned_res,
|
||||
access_type: Some(AssetUsageAccessType::R),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for file in ansible_reqs.file_resources {
|
||||
if let ResourceOrVariablePath::Resource(resource) = file.resource_path {
|
||||
assets.push(ParseAssetsResult {
|
||||
kind: AssetKind::Resource,
|
||||
path: resource,
|
||||
access_type: Some(AssetUsageAccessType::R),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(merge_assets(assets))
|
||||
}
|
||||
|
||||
@@ -1,15 +1,26 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use serde::Serialize;
|
||||
use serde_json::json;
|
||||
use windmill_parser::{Arg, MainArgSignature, ObjectProperty, ObjectType, Typ};
|
||||
use yaml_rust::{Yaml, YamlEmitter, YamlLoader};
|
||||
|
||||
pub mod asset_parser;
|
||||
pub use asset_parser::parse_assets;
|
||||
|
||||
pub fn parse_ansible_sig(inner_content: &str) -> anyhow::Result<MainArgSignature> {
|
||||
let docs = YamlLoader::load_from_str(inner_content)
|
||||
.map_err(|e| anyhow!("Failed to parse yaml: {}", e))?;
|
||||
|
||||
if docs.len() < 2 {
|
||||
let mut delegating_to_git_repo = false;
|
||||
if let Yaml::Hash(doc) = &docs[0] {
|
||||
if let Some(v) = doc.get(&Yaml::String("delegate_to_git_repo".to_string())) {
|
||||
delegating_to_git_repo = extract_delegate_to_git_repo_details(v).is_some();
|
||||
}
|
||||
}
|
||||
|
||||
if docs.len() < 2 && !delegating_to_git_repo {
|
||||
return Ok(MainArgSignature {
|
||||
star_args: false,
|
||||
star_kwargs: false,
|
||||
@@ -56,7 +67,21 @@ pub fn parse_ansible_sig(inner_content: &str) -> anyhow::Result<MainArgSignature
|
||||
has_default: inv.default.is_some(),
|
||||
default: inv.default.map(|v| json!(format!("$res:{}", v))),
|
||||
oidx: None,
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
Yaml::String(key) if key == "additional_inventories" => {
|
||||
for inv in parse_additional_inventories(value)? {
|
||||
if let PreexistingAnsibleInventory::PassedInArgs(i) = inv {
|
||||
args.push(Arg {
|
||||
name: i.name,
|
||||
otyp: None,
|
||||
typ: Typ::List(Box::new(Typ::Str(i.options))),
|
||||
has_default: false,
|
||||
default: None,
|
||||
oidx: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
@@ -211,6 +236,18 @@ pub struct AnsibleInventory {
|
||||
pub pinned_resource: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum PreexistingAnsibleInventory {
|
||||
Static(String),
|
||||
PassedInArgs(InventoryFilenameListDefinition),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct InventoryFilenameListDefinition {
|
||||
pub options: Option<Vec<String>>,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GitRepo {
|
||||
pub url: String,
|
||||
@@ -219,12 +256,22 @@ pub struct GitRepo {
|
||||
pub target_path: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct DelegateToGitRepoDetails {
|
||||
pub resource: String,
|
||||
pub playbook: Option<String>,
|
||||
pub commit: Option<String>,
|
||||
pub inventories_location: Option<String>,
|
||||
pub vars_location: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AnsibleRequirements {
|
||||
pub python_reqs: Vec<String>,
|
||||
pub roles_and_collections: Option<String>,
|
||||
pub file_resources: Vec<FileResource>,
|
||||
pub inventories: Vec<AnsibleInventory>,
|
||||
pub additional_inventories: Vec<PreexistingAnsibleInventory>,
|
||||
pub vars: Vec<(String, String)>,
|
||||
pub resources: Vec<(String, String)>,
|
||||
pub options: AnsiblePlaybookOptions,
|
||||
@@ -232,6 +279,7 @@ pub struct AnsibleRequirements {
|
||||
pub vault_id: Vec<String>,
|
||||
pub git_repos: Vec<GitRepo>,
|
||||
pub git_ssh_identity: Vec<String>,
|
||||
pub delegate_to_git_repo: Option<DelegateToGitRepoDetails>,
|
||||
}
|
||||
|
||||
impl Default for AnsibleRequirements {
|
||||
@@ -241,6 +289,7 @@ impl Default for AnsibleRequirements {
|
||||
roles_and_collections: None,
|
||||
file_resources: vec![],
|
||||
inventories: vec![],
|
||||
additional_inventories: vec![],
|
||||
vars: vec![],
|
||||
resources: vec![],
|
||||
options: AnsiblePlaybookOptions {
|
||||
@@ -254,10 +303,57 @@ impl Default for AnsibleRequirements {
|
||||
vault_id: vec![],
|
||||
git_repos: vec![],
|
||||
git_ssh_identity: vec![],
|
||||
delegate_to_git_repo: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_additional_inventories(
|
||||
inventory_yaml: &Yaml,
|
||||
) -> anyhow::Result<Vec<PreexistingAnsibleInventory>> {
|
||||
if let Yaml::Array(arr) = inventory_yaml {
|
||||
let mut ret = vec![];
|
||||
let mut count = -1;
|
||||
for inv in arr {
|
||||
if let Yaml::String(inv_name) = inv {
|
||||
ret.push(PreexistingAnsibleInventory::Static(inv_name.clone()));
|
||||
} else if let Yaml::Hash(inv) = inv {
|
||||
if let Some(options) = inv.get(&Yaml::String("options".to_string())) {
|
||||
let options = match options {
|
||||
Yaml::Null => None,
|
||||
Yaml::Array(elements) => Some(
|
||||
elements
|
||||
.iter()
|
||||
.filter_map(|s| s.as_str().map(|s| s.to_string()))
|
||||
.collect(),
|
||||
),
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let name = inv
|
||||
.get(&Yaml::String("name".to_string()))
|
||||
.and_then(|v| v.as_str())
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or_else(|| {
|
||||
count += 1;
|
||||
if count == 0 {
|
||||
"Additional inventories".to_string()
|
||||
} else {
|
||||
format!("Additional inventories ({count})")
|
||||
}
|
||||
});
|
||||
|
||||
ret.push(PreexistingAnsibleInventory::PassedInArgs(
|
||||
InventoryFilenameListDefinition { options, name },
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ok(ret);
|
||||
}
|
||||
return Err(anyhow!("Invalid inventory definition"));
|
||||
}
|
||||
|
||||
fn parse_inventories(inventory_yaml: &Yaml) -> anyhow::Result<Vec<AnsibleInventory>> {
|
||||
if let Yaml::Array(arr) = inventory_yaml {
|
||||
let mut ret = vec![];
|
||||
@@ -303,6 +399,33 @@ fn parse_inventories(inventory_yaml: &Yaml) -> anyhow::Result<Vec<AnsibleInvento
|
||||
return Err(anyhow!("Invalid inventory definition"));
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct DelegateWithSSHAuth {
|
||||
delegate_to_git_repo_details: Option<DelegateToGitRepoDetails>,
|
||||
git_ssh_identity: Vec<String>,
|
||||
}
|
||||
|
||||
pub fn parse_delegate_to_git_repo(inner_content: &str) -> anyhow::Result<DelegateWithSSHAuth> {
|
||||
let docs = YamlLoader::load_from_str(inner_content)
|
||||
.map_err(|e| anyhow!("Failed to parse yaml: {}", e))?;
|
||||
|
||||
let mut git_ssh_identity: Vec<String> = vec![];
|
||||
|
||||
if let Yaml::Hash(doc) = &docs[0] {
|
||||
if let Some(v) = doc.get(&Yaml::String("git_ssh_identity".to_string())) {
|
||||
let _ = extract_ssh_identity(&v, &mut git_ssh_identity);
|
||||
}
|
||||
if let Some(v) = doc.get(&Yaml::String("delegate_to_git_repo".to_string())) {
|
||||
return Ok(DelegateWithSSHAuth {
|
||||
delegate_to_git_repo_details: extract_delegate_to_git_repo_details(v),
|
||||
git_ssh_identity,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(DelegateWithSSHAuth { delegate_to_git_repo_details: None, git_ssh_identity })
|
||||
}
|
||||
|
||||
pub fn parse_ansible_reqs(
|
||||
inner_content: &str,
|
||||
) -> anyhow::Result<(String, Option<AnsibleRequirements>, String)> {
|
||||
@@ -310,11 +433,17 @@ pub fn parse_ansible_reqs(
|
||||
let docs = YamlLoader::load_from_str(inner_content)
|
||||
.map_err(|e| anyhow!("Failed to parse yaml: {}", e))?;
|
||||
|
||||
if docs.len() < 2 {
|
||||
return Ok((logs, None, inner_content.to_string()));
|
||||
let mut ret = AnsibleRequirements::default();
|
||||
|
||||
if let Yaml::Hash(doc) = &docs[0] {
|
||||
if let Some(v) = doc.get(&Yaml::String("delegate_to_git_repo".to_string())) {
|
||||
ret.delegate_to_git_repo = extract_delegate_to_git_repo_details(v);
|
||||
}
|
||||
}
|
||||
|
||||
let mut ret = AnsibleRequirements::default();
|
||||
if ret.delegate_to_git_repo.is_none() && docs.len() < 2 {
|
||||
return Ok((logs, None, inner_content.to_string()));
|
||||
}
|
||||
|
||||
if let Yaml::Hash(doc) = &docs[0] {
|
||||
for (key, value) in doc {
|
||||
@@ -367,7 +496,11 @@ pub fn parse_ansible_reqs(
|
||||
}
|
||||
}
|
||||
Yaml::String(key) if key == "inventory" => {
|
||||
ret.inventories = parse_inventories(value)?;
|
||||
ret.inventories.extend(parse_inventories(value)?);
|
||||
}
|
||||
Yaml::String(key) if key == "additional_inventories" => {
|
||||
ret.additional_inventories
|
||||
.extend(parse_additional_inventories(value)?);
|
||||
}
|
||||
Yaml::String(key) if key == "vault_password" => {
|
||||
let Yaml::String(filename) = value else {
|
||||
@@ -407,27 +540,15 @@ pub fn parse_ansible_reqs(
|
||||
}
|
||||
}
|
||||
Yaml::String(key) if key == "git_ssh_identity" => {
|
||||
let Yaml::Array(indentities) = &value else {
|
||||
return Err(anyhow!(
|
||||
"git_ssh_identity expects an array of windmill variables (or secrets) containing ssh IDs"
|
||||
));
|
||||
};
|
||||
|
||||
for r in indentities {
|
||||
let Yaml::String(file_name) = r else {
|
||||
return Err(anyhow!(
|
||||
"Git ssh identity file must be a string path to a Windmill variable/secret"
|
||||
));
|
||||
};
|
||||
|
||||
ret.git_ssh_identity.push(file_name.clone());
|
||||
}
|
||||
extract_ssh_identity(&value, &mut ret.git_ssh_identity)?;
|
||||
}
|
||||
Yaml::String(key) if key == "delegate_to_git_repo" => {} // Skip this because it was already parsed before
|
||||
Yaml::String(key) => logs.push_str(&format!("\nUnknown field `{}`. Ignoring", key)),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut out_str = String::new();
|
||||
let mut emitter = YamlEmitter::new(&mut out_str);
|
||||
|
||||
@@ -437,6 +558,61 @@ pub fn parse_ansible_reqs(
|
||||
Ok((logs, Some(ret), out_str))
|
||||
}
|
||||
|
||||
fn extract_ssh_identity(value: &Yaml, ret: &mut Vec<String>) -> anyhow::Result<()> {
|
||||
let Yaml::Array(indentities) = value else {
|
||||
return Err(anyhow!(
|
||||
"git_ssh_identity expects an array of windmill variables (or secrets) containing ssh IDs"
|
||||
));
|
||||
};
|
||||
|
||||
for r in indentities {
|
||||
let Yaml::String(file_name) = r else {
|
||||
return Err(anyhow!(
|
||||
"Git ssh identity file must be a string path to a Windmill variable/secret"
|
||||
));
|
||||
};
|
||||
|
||||
ret.push(file_name.clone());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn extract_delegate_to_git_repo_details(value: &Yaml) -> Option<DelegateToGitRepoDetails> {
|
||||
if let Yaml::Hash(v) = value {
|
||||
if let Some(resource) = v
|
||||
.get(&Yaml::String("resource".to_string()))
|
||||
.and_then(|s| s.as_str())
|
||||
.map(|s| s.to_string())
|
||||
{
|
||||
let playbook = v
|
||||
.get(&Yaml::String("playbook".to_string()))
|
||||
.and_then(|s| s.as_str())
|
||||
.map(|s| s.to_string());
|
||||
let commit = v
|
||||
.get(&Yaml::String("commit".to_string()))
|
||||
.and_then(|s| s.as_str())
|
||||
.map(|s| s.to_string());
|
||||
let inventories_location = v
|
||||
.get(&Yaml::String("inventories_location".to_string()))
|
||||
.and_then(|s| s.as_str())
|
||||
.map(|s| s.to_string());
|
||||
let vars_location = v
|
||||
.get(&Yaml::String("vars_location".to_string()))
|
||||
.and_then(|s| s.as_str())
|
||||
.map(|s| s.to_string());
|
||||
|
||||
return Some(DelegateToGitRepoDetails {
|
||||
resource,
|
||||
playbook,
|
||||
commit,
|
||||
inventories_location,
|
||||
vars_location,
|
||||
});
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
fn parse_git_repo(r: &Yaml) -> anyhow::Result<GitRepo> {
|
||||
let Yaml::Hash(repo) = r else {
|
||||
return Err(anyhow!("Should be a Map"));
|
||||
@@ -679,7 +855,7 @@ pub fn add_versions_to_requirements_yaml(
|
||||
input: &str,
|
||||
role_versions: &HashMap<String, String>,
|
||||
collection_versions: &HashMap<String, String>,
|
||||
) -> anyhow::Result<(String,String)> {
|
||||
) -> anyhow::Result<(String, String)> {
|
||||
let mut docs =
|
||||
YamlLoader::load_from_str(input).map_err(|e| anyhow!("YAML parse error: {}", e))?;
|
||||
let doc = &mut docs[0];
|
||||
@@ -709,3 +885,89 @@ pub fn add_versions_to_requirements_yaml(
|
||||
|
||||
Ok((out_str, logs))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parse_ansible_assets() {
|
||||
let p = r#"
|
||||
---
|
||||
inventory:
|
||||
- resource_type: ansible_inventory
|
||||
# You can pin an inventory to this script by hardcoding the resource path:
|
||||
# resource: u/user/your_resource
|
||||
# - name: hcloud.yml
|
||||
# resource_type: dynamic_inventory
|
||||
|
||||
additional_inventories:
|
||||
- options: ["a", "b", "c"]
|
||||
|
||||
options:
|
||||
- verbosity: vvv
|
||||
|
||||
delegate_to_git_repo:
|
||||
resource: u/admin/git_reportino
|
||||
playbook: ./playbooks/playbook.yml
|
||||
commit: 7sh7dh73h7dhd299d91hd1hdh3d3hygh4372
|
||||
|
||||
|
||||
# File resources will be written in the relative `target` location before
|
||||
# running the playbook
|
||||
files:
|
||||
- resource: u/user/fabulous_jinja_template
|
||||
target: ./config_template.j2
|
||||
- variable: u/user/ssh_key
|
||||
target: ./ssh_key
|
||||
mode: '0600'
|
||||
|
||||
# Define the arguments of the windmill script
|
||||
extra_vars:
|
||||
world_qualifier:
|
||||
type: string
|
||||
|
||||
# If using Ansible Vault:
|
||||
# vault_password: u/user/ansible_vault_password
|
||||
|
||||
dependencies:
|
||||
galaxy:
|
||||
collections:
|
||||
- name: community.general
|
||||
- name: community.vmware
|
||||
roles:
|
||||
python:
|
||||
- jmespath
|
||||
---
|
||||
- name: Echo
|
||||
hosts: 127.0.0.1
|
||||
connection: local
|
||||
vars:
|
||||
my_result:
|
||||
a: 2
|
||||
b: true
|
||||
c: "Hello"
|
||||
|
||||
tasks:
|
||||
- name: Print debug message
|
||||
debug:
|
||||
msg: "Hello, {{world_qualifier}} world!"
|
||||
- name: Write variable my_result to result.json
|
||||
delegate_to: localhost
|
||||
copy:
|
||||
content: "{{ my_result | to_json }}"
|
||||
dest: result.json
|
||||
"#;
|
||||
let a = parse_assets(p).unwrap();
|
||||
println!("The resulting assets are: {}", a.len());
|
||||
|
||||
let a = parse_ansible_reqs(p).unwrap();
|
||||
println!("The resulting reqs are: {:#?}", a);
|
||||
|
||||
let a = parse_ansible_sig(p).unwrap();
|
||||
println!("The resulting sig is: {:#?}", a);
|
||||
|
||||
let a = parse_delegate_to_git_repo(p).unwrap();
|
||||
println!("The resulting delegate_to_kit_repo is: {:#?}", a);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,13 @@ pub struct ParseAssetsResult<S: AsRef<str>> {
|
||||
pub access_type: Option<AssetUsageAccessType>, // None in case of ambiguity
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
pub struct DelegateToGitRepoDetails {
|
||||
pub resource: String,
|
||||
pub playbook: Option<String>,
|
||||
pub commit: Option<String>,
|
||||
}
|
||||
|
||||
pub fn merge_assets<S: AsRef<str>>(assets: Vec<ParseAssetsResult<S>>) -> Vec<ParseAssetsResult<S>> {
|
||||
let mut arr: Vec<ParseAssetsResult<S>> = vec![];
|
||||
for asset in assets {
|
||||
|
||||
@@ -1588,6 +1588,7 @@ pub async fn monitor_db(
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// run every hour (60 minutes / 30 seconds = 120)
|
||||
let cleanup_worker_group_stats_f = async {
|
||||
if server_mode && iteration.is_some() && iteration.as_ref().unwrap().should_run(120) {
|
||||
@@ -2415,6 +2416,7 @@ async fn cleanup_concurrency_counters_empty_keys(db: &DB) -> error::Result<()> {
|
||||
WITH rows_to_delete AS (
|
||||
SELECT concurrency_id
|
||||
FROM concurrency_counter
|
||||
|
||||
WHERE job_uuids = '{}'::jsonb
|
||||
FOR UPDATE SKIP LOCKED
|
||||
)
|
||||
@@ -2724,7 +2726,7 @@ pub async fn reload_critical_alerts_on_db_oversize(conn: &DB) -> error::Result<(
|
||||
async fn generate_and_save_jwt_secret(db: &DB) -> error::Result<String> {
|
||||
let secret = rd_string(32);
|
||||
sqlx::query!(
|
||||
"INSERT INTO global_settings (name, value) VALUES ($1, $2) ON CONFLICT (name) DO UPDATE SET value = $2",
|
||||
"INSERT INTO global_settings (name, value) VALUES ($1, $2) ON CONFLICT (name) DO UPDATE SET value = EXCLUDED.value",
|
||||
JWT_SECRET_SETTING,
|
||||
serde_json::to_value(&secret).unwrap()
|
||||
).execute(db).await?;
|
||||
|
||||
+45
-15
@@ -20,6 +20,17 @@ use windmill_common::{
|
||||
};
|
||||
use windmill_queue::PushIsolationLevel;
|
||||
|
||||
pub async fn init_client(db: Pool<Postgres>) -> (windmill_api_client::Client, u16, ApiServer) {
|
||||
initialize_tracing().await;
|
||||
let server = ApiServer::start(db).await.unwrap();
|
||||
let port = server.addr.port();
|
||||
let client = windmill_api_client::create_client(
|
||||
&format!("http://localhost:{port}"),
|
||||
"SECRET_TOKEN".to_string(),
|
||||
);
|
||||
(client, port, server)
|
||||
}
|
||||
|
||||
/// it's important this is unique between tests as there is one prometheus registry and
|
||||
/// run_worker shouldn't register the same metric with the same worker name more than once.
|
||||
///
|
||||
@@ -131,7 +142,7 @@ impl RunJob {
|
||||
|
||||
let tx = PushIsolationLevel::IsolatedRoot(db.clone());
|
||||
let (uuid, tx) = windmill_queue::push(
|
||||
&db,
|
||||
db,
|
||||
tx,
|
||||
"test-workspace",
|
||||
payload,
|
||||
@@ -157,6 +168,7 @@ impl RunJob {
|
||||
None,
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.expect("push has to succeed");
|
||||
@@ -170,8 +182,8 @@ impl RunJob {
|
||||
let uuid = self.push(db).await;
|
||||
let listener = listen_for_completed_jobs(db).await;
|
||||
in_test_worker(db, listener.find(&uuid), port).await;
|
||||
let r = completed_job(uuid, db).await;
|
||||
r
|
||||
|
||||
completed_job(uuid, db).await
|
||||
}
|
||||
|
||||
/// push the job, spawn a worker, wait until the job is in completed_job
|
||||
@@ -185,8 +197,8 @@ impl RunJob {
|
||||
let listener = listen_for_completed_jobs(db).await;
|
||||
test(uuid).await;
|
||||
in_test_worker(db, listener.find(&uuid), port).await;
|
||||
let r = completed_job(uuid, db).await;
|
||||
r
|
||||
|
||||
completed_job(uuid, db).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,10 +263,10 @@ pub fn spawn_test_worker(
|
||||
let base_internal_url = format!("http://localhost:{}", port);
|
||||
{
|
||||
let mut wc = WORKER_CONFIG.write().await;
|
||||
(*wc).worker_tags = windmill_common::worker::DEFAULT_TAGS.clone();
|
||||
(*wc).priority_tags_sorted = vec![windmill_common::worker::PriorityTags {
|
||||
wc.worker_tags = windmill_common::worker::DEFAULT_TAGS.clone();
|
||||
wc.priority_tags_sorted = vec![windmill_common::worker::PriorityTags {
|
||||
priority: 0,
|
||||
tags: (*wc).worker_tags.clone(),
|
||||
tags: wc.worker_tags.clone(),
|
||||
}];
|
||||
windmill_common::worker::store_suspended_pull_query(&wc).await;
|
||||
windmill_common::worker::store_pull_query(&wc).await;
|
||||
@@ -349,7 +361,7 @@ fn find_module_in_vec(modules: Vec<FlowStatusModule>, id: &str) -> Option<FlowSt
|
||||
modules.into_iter().find(|s| s.id() == id)
|
||||
}
|
||||
|
||||
pub async fn set_jwt_secret() -> () {
|
||||
pub async fn set_jwt_secret() {
|
||||
let secret = "mytestsecret".to_string();
|
||||
let mut l = JWT_SECRET.write().await;
|
||||
*l = secret;
|
||||
@@ -475,10 +487,10 @@ pub async fn assert_lockfile(
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut completed = listen_for_completed_jobs(&db).await;
|
||||
let mut completed = listen_for_completed_jobs(db).await;
|
||||
let db2 = db.clone();
|
||||
in_test_worker(
|
||||
&db,
|
||||
db,
|
||||
async move {
|
||||
completed.next().await; // deployed script
|
||||
|
||||
@@ -571,10 +583,10 @@ pub async fn run_deployed_relative_imports(
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let mut completed = listen_for_completed_jobs(&db).await;
|
||||
let mut completed = listen_for_completed_jobs(db).await;
|
||||
let db2 = db.clone();
|
||||
in_test_worker(
|
||||
&db,
|
||||
db,
|
||||
async move {
|
||||
completed.next().await; // deployed script
|
||||
|
||||
@@ -631,10 +643,10 @@ pub async fn run_preview_relative_imports(
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
let port = server.addr.port();
|
||||
|
||||
let mut completed = listen_for_completed_jobs(&db).await;
|
||||
let mut completed = listen_for_completed_jobs(db).await;
|
||||
let db2 = db.clone();
|
||||
in_test_worker(
|
||||
&db,
|
||||
db,
|
||||
async move {
|
||||
let job = RunJob::from(JobPayload::Code(RawCode {
|
||||
hash: None,
|
||||
@@ -671,3 +683,21 @@ pub async fn run_preview_relative_imports(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// IMPORTANT!:
|
||||
/// Do not run parallel in tests!
|
||||
///
|
||||
/// No tests can run this at the same time, will result into conflicts!!!
|
||||
pub async fn rebuild_dmap(client: &windmill_api_client::Client) -> bool {
|
||||
client
|
||||
.client()
|
||||
.post(format!(
|
||||
"{}/w/test-workspace/workspaces/rebuild_dependency_map",
|
||||
client.baseurl()
|
||||
))
|
||||
.send()
|
||||
.await
|
||||
.unwrap()
|
||||
.status()
|
||||
.is_success()
|
||||
}
|
||||
|
||||
+242
File diff suppressed because one or more lines are too long
@@ -10,6 +10,7 @@ mod job_payload {
|
||||
use windmill_common::jobs::JobPayload;
|
||||
use windmill_common::flows::{FlowValue, FlowModule, FlowModuleValue};
|
||||
use windmill_common::flow_status::RestartedFrom;
|
||||
|
||||
use windmill_common::worker::{
|
||||
MIN_VERSION_IS_AT_LEAST_1_427, MIN_VERSION_IS_AT_LEAST_1_432, MIN_VERSION_IS_AT_LEAST_1_440,
|
||||
};
|
||||
|
||||
+1898
-83
File diff suppressed because it is too large
Load Diff
+9
-12
@@ -20,7 +20,6 @@ use windmill_common::flows::InputTransform;
|
||||
|
||||
#[cfg(any(feature = "python", feature = "deno_core"))]
|
||||
use windmill_common::flow_status::RestartedFrom;
|
||||
|
||||
use windmill_common::{
|
||||
flows::FlowValue,
|
||||
jobs::{JobPayload, RawCode},
|
||||
@@ -31,6 +30,8 @@ use common::*;
|
||||
|
||||
#[cfg(feature = "enterprise")]
|
||||
use futures::StreamExt;
|
||||
use windmill_common::flows::FlowModule;
|
||||
use windmill_common::flows::FlowModuleValue;
|
||||
|
||||
// async fn _print_job(id: Uuid, db: &Pool<Postgres>) -> Result<(), anyhow::Error> {
|
||||
// tracing::info!(
|
||||
@@ -332,9 +333,6 @@ async fn test_identity(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
use windmill_common::flows::FlowModule;
|
||||
use windmill_common::flows::FlowModuleValue;
|
||||
|
||||
#[cfg(feature = "deno_core")]
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
async fn test_deno_flow_same_worker(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
@@ -2083,14 +2081,14 @@ async fn test_flow_lock_all(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
language: windmill_api_client::types::RawScriptLanguage::Bash,
|
||||
lock: Some(ref lock),
|
||||
..
|
||||
}) if lock == "")
|
||||
}) if lock.is_empty())
|
||||
|| matches!(
|
||||
m.value,
|
||||
windmill_api_client::types::FlowModuleValue::RawScript(RawScript{
|
||||
language: windmill_api_client::types::RawScriptLanguage::Go | windmill_api_client::types::RawScriptLanguage::Python3 | windmill_api_client::types::RawScriptLanguage::Deno,
|
||||
lock: Some(ref lock),
|
||||
..
|
||||
}) if lock.len() > 0),
|
||||
}) if !lock.is_empty()),
|
||||
"{:?}", m.value
|
||||
);
|
||||
});
|
||||
@@ -2749,7 +2747,7 @@ async fn test_result_format(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
assert_eq!(job_result.get(), correct_result);
|
||||
|
||||
let response = windmill_api::jobs::run_wait_result(
|
||||
&db.into(),
|
||||
&db,
|
||||
Uuid::parse_str(ordered_result_job_id).unwrap(),
|
||||
"test-workspace".to_string(),
|
||||
None,
|
||||
@@ -2760,8 +2758,7 @@ async fn test_result_format(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
let result: Box<serde_json::value::RawValue> = serde_json::from_slice(
|
||||
&axum::body::to_bytes(response.into_body(), usize::MAX)
|
||||
.await
|
||||
.unwrap()
|
||||
.to_vec(),
|
||||
.unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(result.get(), correct_result);
|
||||
@@ -2805,7 +2802,7 @@ async fn test_job_labels(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
restarted_from: None,
|
||||
})
|
||||
.arg("world", json!("you"))
|
||||
.run_until_complete_with(&db, port, |id| async move {
|
||||
.run_until_complete_with(db, port, |id| async move {
|
||||
sqlx::query!(
|
||||
"UPDATE v2_job SET labels = $2 WHERE id = $1 AND $2::TEXT[] IS NOT NULL",
|
||||
id,
|
||||
@@ -2871,7 +2868,7 @@ async fn test_workflow_as_code(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
// workflow as code require at least 2 workers:
|
||||
let db = &db;
|
||||
in_test_worker(
|
||||
&db,
|
||||
db,
|
||||
async move {
|
||||
let job = RunJob::from(JobPayload::Code(RawCode {
|
||||
language: ScriptLang::Python3,
|
||||
@@ -2879,7 +2876,7 @@ async fn test_workflow_as_code(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
..RawCode::default()
|
||||
}))
|
||||
.arg("n", json!(3))
|
||||
.run_until_complete(&db, port)
|
||||
.run_until_complete(db, port)
|
||||
.await;
|
||||
|
||||
assert_eq!(job.json_result().unwrap(), json!(["OK", 3]));
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
openapi: "3.0.3"
|
||||
|
||||
info:
|
||||
version: 1.559.0
|
||||
version: 1.562.0
|
||||
title: Windmill API
|
||||
|
||||
contact:
|
||||
@@ -4192,6 +4192,33 @@ paths:
|
||||
application/json:
|
||||
schema: {}
|
||||
|
||||
/w/{workspace}/resources/git_commit_hash/{path}:
|
||||
get:
|
||||
summary: get git repository latest commit hash
|
||||
operationId: getGitCommitHash
|
||||
tags:
|
||||
- resource
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- $ref: "#/components/parameters/Path"
|
||||
- name: git_ssh_identity
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: git commit hash
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
commit_hash:
|
||||
type: string
|
||||
description: Latest commit hash from git ls-remote
|
||||
required:
|
||||
- commit_hash
|
||||
|
||||
/w/{workspace}/resources/exists/{path}:
|
||||
get:
|
||||
summary: does resource exists
|
||||
@@ -13441,6 +13468,160 @@ paths:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WindmillFilePreview"
|
||||
|
||||
/w/{workspace}/job_helpers/list_git_repo_files:
|
||||
get:
|
||||
summary: List the file keys available in instance object storage with resource-based access control
|
||||
operationId: listGitRepoFiles
|
||||
tags:
|
||||
- helpers
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- name: max_keys
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
- name: marker
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
- name: prefix
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
description: Must follow format gitrepos/{workspace_id}/{resource_path}/...
|
||||
- name: storage
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: List of file keys
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
next_marker:
|
||||
type: string
|
||||
windmill_large_files:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/WindmillLargeFile"
|
||||
restricted_access:
|
||||
type: boolean
|
||||
required:
|
||||
- windmill_large_files
|
||||
|
||||
/w/{workspace}/job_helpers/load_git_repo_file_preview:
|
||||
get:
|
||||
summary: Load a preview of a file from instance storage with resource-based access control
|
||||
operationId: loadGitRepoFilePreview
|
||||
tags:
|
||||
- helpers
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- name: file_key
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
description: Must follow format gitrepos/{workspace_id}/{resource_path}/...
|
||||
- name: file_size_in_bytes
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
- name: file_mime_type
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
- name: csv_separator
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
- name: csv_has_header
|
||||
in: query
|
||||
schema:
|
||||
type: boolean
|
||||
- name: read_bytes_from
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
- name: read_bytes_length
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
- name: storage
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: FilePreview
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WindmillFilePreview"
|
||||
|
||||
/w/{workspace}/job_helpers/load_git_repo_file_metadata:
|
||||
get:
|
||||
summary: Load file metadata from instance storage with resource-based access control
|
||||
operationId: loadGitRepoFileMetadata
|
||||
tags:
|
||||
- helpers
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- name: file_key
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
description: Must follow format gitrepos/{workspace_id}/{resource_path}/...
|
||||
- name: storage
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: FileMetadata
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WindmillFileMetadata"
|
||||
|
||||
/w/{workspace}/job_helpers/check_s3_folder_exists:
|
||||
get:
|
||||
summary: Check if S3 path exists and is a folder
|
||||
operationId: checkS3FolderExists
|
||||
tags:
|
||||
- helpers
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- name: file_key
|
||||
description: S3 file key to check (e.g., gitrepos/{workspace_id}/u/user/resource/{commit_hash})
|
||||
in: query
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: S3 folder existence check result
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
exists:
|
||||
type: boolean
|
||||
description: Whether the path exists
|
||||
is_folder:
|
||||
type: boolean
|
||||
description: Whether the path is a folder (true) or file (false)
|
||||
required:
|
||||
- exists
|
||||
- is_folder
|
||||
|
||||
/w/{workspace}/job_helpers/load_parquet_preview/{path}:
|
||||
get:
|
||||
summary: Load a preview of a parquet file
|
||||
@@ -13677,6 +13858,67 @@ paths:
|
||||
required:
|
||||
- file_key
|
||||
|
||||
/w/{workspace}/job_helpers/upload_git_repo_file_to_instance_storage:
|
||||
post:
|
||||
summary: Upload a file to the instance storage gitrepos section for viewing
|
||||
operationId: gitRepoViewerFileUpload
|
||||
tags:
|
||||
- helpers
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/WorkspaceId"
|
||||
- name: file_key
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
- name: file_extension
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
- name: s3_resource_path
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
- name: resource_type
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
- name: storage
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
- name: content_type
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
- name: content_disposition
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
requestBody:
|
||||
description: File content
|
||||
required: true
|
||||
content:
|
||||
application/octet-stream:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
responses:
|
||||
"200":
|
||||
description: File upload status
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
file_key:
|
||||
type: string
|
||||
required:
|
||||
- file_key
|
||||
|
||||
/w/{workspace}/job_helpers/download_s3_file:
|
||||
get:
|
||||
summary: Download file from S3 bucket
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
use crate::{
|
||||
db::{ApiAuthed, DB},
|
||||
variables::get_variable_or_self,
|
||||
};
|
||||
use crate::db::{ApiAuthed, DB};
|
||||
|
||||
use axum::{body::Bytes, extract::Path, response::IntoResponse, routing::post, Extension, Router};
|
||||
use http::{HeaderMap, Method};
|
||||
@@ -9,6 +6,7 @@ use quick_cache::sync::Cache;
|
||||
use reqwest::{Client, RequestBuilder};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::value::RawValue;
|
||||
use windmill_common::variables::get_variable_or_self;
|
||||
use std::collections::HashMap;
|
||||
use windmill_audit::{audit_oss::audit_log, ActionKind};
|
||||
use windmill_common::ai_providers::{AIProvider, ProviderConfig, ProviderModel, AZURE_API_VERSION};
|
||||
|
||||
@@ -60,7 +60,7 @@ use windmill_common::{
|
||||
users::username_to_permissioned_as,
|
||||
utils::{
|
||||
http_get_from_hub, not_found_if_none, paginate, query_elems_from_hub, require_admin,
|
||||
Pagination, RunnableKind, StripPath,
|
||||
Pagination, RunnableKind, StripPath, WarnAfterExt,
|
||||
},
|
||||
variables::{build_crypt, build_crypt_with_key_suffix, encrypt},
|
||||
worker::{to_raw_value, CLOUD_HOSTED},
|
||||
@@ -699,7 +699,7 @@ async fn update_app_history(
|
||||
check_scopes(&authed, || format!("apps:write:{}", &app_path))?;
|
||||
|
||||
sqlx::query!(
|
||||
"INSERT INTO deployment_metadata (workspace_id, path, app_version, deployment_msg) VALUES ($1, $2, $3, $4) ON CONFLICT (workspace_id, path, app_version) WHERE app_version IS NOT NULL DO UPDATE SET deployment_msg = $4",
|
||||
"INSERT INTO deployment_metadata (workspace_id, path, app_version, deployment_msg) VALUES ($1, $2, $3, $4) ON CONFLICT (workspace_id, path, app_version) WHERE app_version IS NOT NULL DO UPDATE SET deployment_msg = EXCLUDED.deployment_msg",
|
||||
w_id,
|
||||
app_path,
|
||||
app_version,
|
||||
@@ -1240,6 +1240,7 @@ async fn create_app_internal<'a>(
|
||||
Some(&authed.clone().into()),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
tracing::info!("Pushed app dependency job {}", dependency_job_uuid);
|
||||
@@ -1523,6 +1524,14 @@ async fn update_app_internal<'a>(
|
||||
path.to_owned()
|
||||
};
|
||||
let v_id = if let Some(nvalue) = &ns.value {
|
||||
// Row lock debounce key for path. We need this to make all updates of runnables sequential and predictable.
|
||||
tokio::time::timeout(
|
||||
core::time::Duration::from_secs(60),
|
||||
windmill_common::jobs::lock_debounce_key(&w_id, &npath, &mut tx),
|
||||
)
|
||||
.warn_after_seconds(10)
|
||||
.await??;
|
||||
|
||||
let app_id = sqlx::query_scalar!(
|
||||
"SELECT id FROM app WHERE path = $1 AND workspace_id = $2",
|
||||
npath,
|
||||
@@ -1620,6 +1629,7 @@ async fn update_app_internal<'a>(
|
||||
Some(&authed.clone().into()),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
tracing::info!("Pushed app dependency job {}", dependency_job_uuid);
|
||||
@@ -1938,6 +1948,7 @@ async fn execute_component(
|
||||
None,
|
||||
false,
|
||||
end_user_email,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
|
||||
@@ -159,22 +159,22 @@ async fn get_concurrent_intervals(
|
||||
let lq = ListCompletedQuery { order_desc: Some(true), ..lq };
|
||||
let lqc = lq.clone();
|
||||
let lqq: ListQueueQuery = lqc.into();
|
||||
let mut sqlb_q = SqlBuilder::select_from("v2_as_queue")
|
||||
let mut sqlb_q = SqlBuilder::select_from("v2_job_queue")
|
||||
.fields(UnifiedJob::queued_job_fields())
|
||||
.order_by("created_at", lq.order_desc.unwrap_or(true))
|
||||
.limit(row_limit)
|
||||
.clone();
|
||||
let mut sqlb_c = SqlBuilder::select_from("v2_as_completed_job")
|
||||
let mut sqlb_c = SqlBuilder::select_from("v2_job_completed")
|
||||
.fields(UnifiedJob::completed_job_fields())
|
||||
.order_by("started_at", lq.order_desc.unwrap_or(true))
|
||||
.limit(row_limit)
|
||||
.clone();
|
||||
let mut sqlb_q_user = SqlBuilder::select_from("v2_as_queue")
|
||||
let mut sqlb_q_user = SqlBuilder::select_from("v2_job_queue")
|
||||
.fields(&["id"])
|
||||
.order_by("created_at", lq.order_desc.unwrap_or(true))
|
||||
.limit(row_limit)
|
||||
.clone();
|
||||
let mut sqlb_c_user = SqlBuilder::select_from("v2_as_completed_job")
|
||||
let mut sqlb_c_user = SqlBuilder::select_from("v2_job_completed")
|
||||
.fields(&["id"])
|
||||
.order_by("started_at", lq.order_desc.unwrap_or(true))
|
||||
.limit(row_limit)
|
||||
|
||||
@@ -173,7 +173,7 @@ async fn update_config(
|
||||
|
||||
let mut tx = db.begin().await?;
|
||||
sqlx::query!(
|
||||
"INSERT INTO config (name, config) VALUES ($1, $2) ON CONFLICT (name) DO UPDATE SET config = $2",
|
||||
"INSERT INTO config (name, config) VALUES ($1, $2) ON CONFLICT (name) DO UPDATE SET config = EXCLUDED.config",
|
||||
&name,
|
||||
config
|
||||
)
|
||||
|
||||
@@ -212,7 +212,7 @@ pub async fn migrate(
|
||||
if let Err(err) = sqlx::query!(
|
||||
"DELETE FROM _sqlx_migrations WHERE
|
||||
version=20250131115248 OR version=20250902085503 OR version=20250201145630 OR
|
||||
version=20250201145631 OR version=20250201145632"
|
||||
version=20250201145631 OR version=20250201145632 OR version=20251006143821"
|
||||
)
|
||||
.execute(db)
|
||||
.await
|
||||
|
||||
@@ -79,7 +79,7 @@ async fn create_draft(
|
||||
"INSERT INTO draft
|
||||
(workspace_id, path, value, typ)
|
||||
VALUES ($1, $2, $3::text::json, $4)
|
||||
ON CONFLICT (workspace_id, path, typ) DO UPDATE SET value = $3::text::json",
|
||||
ON CONFLICT (workspace_id, path, typ) DO UPDATE SET value = EXCLUDED.value",
|
||||
&w_id,
|
||||
draft.path,
|
||||
//to preserve key orders
|
||||
|
||||
@@ -32,7 +32,7 @@ use sql_builder::prelude::*;
|
||||
use sqlx::{FromRow, Postgres, Transaction};
|
||||
use windmill_audit::audit_oss::audit_log;
|
||||
use windmill_audit::ActionKind;
|
||||
use windmill_common::utils::query_elems_from_hub;
|
||||
use windmill_common::utils::{query_elems_from_hub, WarnAfterExt};
|
||||
use windmill_common::worker::{to_raw_value, CLOUD_HOSTED};
|
||||
use windmill_common::HUB_BASE_URL;
|
||||
use windmill_common::{
|
||||
@@ -546,6 +546,7 @@ async fn create_flow(
|
||||
Some(&authed.clone().into()),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -722,7 +723,7 @@ async fn update_flow_history(
|
||||
}
|
||||
|
||||
sqlx::query!(
|
||||
"INSERT INTO deployment_metadata (workspace_id, path, flow_version, deployment_msg) VALUES ($1, $2, $3, $4) ON CONFLICT (workspace_id, path, flow_version) WHERE flow_version IS NOT NULL DO UPDATE SET deployment_msg = $4",
|
||||
"INSERT INTO deployment_metadata (workspace_id, path, flow_version, deployment_msg) VALUES ($1, $2, $3, $4) ON CONFLICT (workspace_id, path, flow_version) WHERE flow_version IS NOT NULL DO UPDATE SET deployment_msg = EXCLUDED.deployment_msg",
|
||||
w_id,
|
||||
path_o.unwrap(),
|
||||
version,
|
||||
@@ -884,6 +885,15 @@ async fn update_flow(
|
||||
.await?;
|
||||
}
|
||||
|
||||
// Row lock debounce key for path. We need this to make all updates of runnables sequential and predictable.
|
||||
tokio::time::timeout(
|
||||
core::time::Duration::from_secs(60),
|
||||
windmill_common::jobs::lock_debounce_key(&w_id, &nf.path, &mut tx),
|
||||
)
|
||||
.warn_after_seconds(10)
|
||||
.await??;
|
||||
|
||||
// This will lock anyone who is trying to iterate on flow_versions with given path and parameters.
|
||||
let version = sqlx::query_scalar!(
|
||||
"INSERT INTO flow_version (workspace_id, path, value, schema, created_by) VALUES ($1, $2, $3, $4::text::json, $5) RETURNING id",
|
||||
w_id,
|
||||
@@ -900,6 +910,7 @@ async fn update_flow(
|
||||
))
|
||||
})?;
|
||||
|
||||
// TODO: This should happen only after we are done with dependency job.
|
||||
sqlx::query!(
|
||||
"UPDATE flow SET versions = array_append(versions, $1) WHERE path = $2 AND workspace_id = $3",
|
||||
version, nf.path, w_id
|
||||
@@ -1014,8 +1025,10 @@ async fn update_flow(
|
||||
Some(&authed.clone().into()),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
sqlx::query!(
|
||||
"UPDATE flow SET dependency_job = $1 WHERE path = $2 AND workspace_id = $3",
|
||||
dependency_job_uuid,
|
||||
|
||||
@@ -286,13 +286,17 @@ async fn create_igroup(
|
||||
Extension(db): Extension<DB>,
|
||||
Json(ng): Json<NewGroup>,
|
||||
) -> Result<String> {
|
||||
use uuid::Uuid;
|
||||
|
||||
require_super_admin(&db, &authed.email).await?;
|
||||
let mut tx = db.begin().await?;
|
||||
|
||||
let id = Uuid::new_v4().to_string();
|
||||
sqlx::query!(
|
||||
"INSERT INTO instance_group (name, summary) VALUES ($1, $2) ON CONFLICT DO NOTHING",
|
||||
"INSERT INTO instance_group (name, summary, id) VALUES ($1, $2, $3) ON CONFLICT DO NOTHING",
|
||||
ng.name,
|
||||
ng.summary,
|
||||
id,
|
||||
)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
|
||||
@@ -4101,6 +4101,7 @@ pub async fn run_flow_by_path_inner(
|
||||
push_authed.as_ref(),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -4217,6 +4218,7 @@ pub async fn restart_flow(
|
||||
Some(&authed.clone().into()),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
@@ -4320,6 +4322,7 @@ pub async fn run_script_by_path_inner(
|
||||
push_authed.as_ref(),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
@@ -4473,6 +4476,7 @@ pub async fn run_workflow_as_code(
|
||||
push_authed.as_ref(),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -5017,6 +5021,7 @@ pub async fn run_wait_result_job_by_path_get(
|
||||
push_authed.as_ref(),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
@@ -5170,6 +5175,7 @@ pub async fn run_wait_result_script_by_path_internal(
|
||||
push_authed.as_ref(),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
@@ -5287,6 +5293,7 @@ pub async fn run_wait_result_script_by_hash(
|
||||
push_authed.as_ref(),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
@@ -5599,6 +5606,7 @@ pub async fn run_wait_result_flow_by_path_internal(
|
||||
push_authed.as_ref(),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -5690,6 +5698,7 @@ async fn run_preview_script(
|
||||
Some(&authed.clone().into()),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
@@ -5807,6 +5816,7 @@ async fn run_bundle_preview_script(
|
||||
Some(&authed.clone().into()),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
job_id = Some(uuid);
|
||||
@@ -5945,6 +5955,7 @@ async fn run_dependencies_job(
|
||||
Some(&authed.clone().into()),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
@@ -6013,6 +6024,7 @@ async fn run_flow_dependencies_job(
|
||||
Some(&authed.clone().into()),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
@@ -6357,6 +6369,7 @@ async fn run_preview_flow_job(
|
||||
Some(&authed.clone().into()),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
@@ -6531,6 +6544,7 @@ async fn run_dynamic_select(
|
||||
Some(&authed.clone().into()),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
@@ -6659,6 +6673,7 @@ pub async fn run_job_by_hash_inner(
|
||||
push_authed.as_ref(),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
@@ -6889,6 +6904,12 @@ enum JobUpdateSSEStream {
|
||||
Ping,
|
||||
}
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref TIMEOUT_SSE_STREAM: u64 =
|
||||
std::env::var("TIMEOUT_SSE_STREAM").unwrap_or("60".to_string()).parse::<u64>().unwrap_or(60);
|
||||
}
|
||||
|
||||
|
||||
fn start_job_update_sse_stream(
|
||||
opt_authed: Option<ApiAuthed>,
|
||||
opt_tokened: OptTokened,
|
||||
@@ -7021,7 +7042,7 @@ fn start_job_update_sse_stream(
|
||||
last_ping = Instant::now();
|
||||
}
|
||||
|
||||
if start.elapsed().as_secs() > 30 {
|
||||
if start.elapsed().as_secs() > *TIMEOUT_SSE_STREAM {
|
||||
if tx.send(JobUpdateSSEStream::Timeout).await.is_err() {
|
||||
tracing::warn!("Failed to send job timeout for job {job_id}");
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ use crate::{
|
||||
users::{maybe_refresh_folders, require_owner_of_path, Tokened},
|
||||
utils::{check_scopes, require_super_admin, BulkDeleteRequest},
|
||||
var_resource_cache::{cache_resource, get_cached_resource},
|
||||
variables::get_value_internal,
|
||||
webhook_util::{WebhookMessage, WebhookShared},
|
||||
};
|
||||
use axum::{
|
||||
@@ -28,16 +29,18 @@ use serde::{Deserialize, Serialize};
|
||||
use serde_json::{value::RawValue, Value};
|
||||
use sql_builder::{bind::Bind, quote, SqlBuilder};
|
||||
use sqlx::{FromRow, Postgres, Transaction};
|
||||
use std::process::Stdio;
|
||||
use tokio::process::Command;
|
||||
use uuid::Uuid;
|
||||
use windmill_audit::audit_oss::{audit_log, AuditAuthor};
|
||||
use windmill_audit::ActionKind;
|
||||
use windmill_common::{
|
||||
db::{UserDB, UserDbWithOptAuthed},
|
||||
error::{Error, JsonResult, Result},
|
||||
db::{UserDB, UserDbWithAuthed, UserDbWithOptAuthed},
|
||||
error::{self, Error, JsonResult, Result},
|
||||
get_database_url, parse_postgres_url,
|
||||
utils::{not_found_if_none, paginate, require_admin, Pagination, StripPath},
|
||||
variables,
|
||||
worker::CLOUD_HOSTED,
|
||||
worker::{CLOUD_HOSTED, TMP_DIR},
|
||||
workspaces::get_ducklake_instance_pg_catalog_password,
|
||||
};
|
||||
|
||||
@@ -58,6 +61,7 @@ pub fn workspaced_service() -> Router {
|
||||
.route("/delete/*path", delete(delete_resource))
|
||||
.route("/delete_bulk", delete(delete_resources_bulk))
|
||||
.route("/create", post(create_resource))
|
||||
.route("/git_commit_hash/*path", get(get_git_commit_hash))
|
||||
.route("/type/list", get(list_resource_types))
|
||||
.route("/type/listnames", get(list_resource_types_names))
|
||||
.route("/type/get/:name", get(get_resource_type))
|
||||
@@ -737,7 +741,7 @@ async fn create_resource(
|
||||
"INSERT INTO resource
|
||||
(workspace_id, path, value, description, resource_type, created_by, edited_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, now()) ON CONFLICT (workspace_id, path)
|
||||
DO UPDATE SET value = $3, description = $4, resource_type = $5, edited_at = now()",
|
||||
DO UPDATE SET value = EXCLUDED.value, description = EXCLUDED.description, resource_type = EXCLUDED.resource_type, edited_at = now()",
|
||||
w_id,
|
||||
resource.path,
|
||||
raw_json as sqlx::types::Json<&RawValue>,
|
||||
@@ -1387,3 +1391,212 @@ where
|
||||
|
||||
Ok(resource)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
struct GitRepositoryResource {
|
||||
url: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
branch: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct GitCommitHashResponse {
|
||||
commit_hash: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct GitCommitHashQuery {
|
||||
git_ssh_identity: Option<String>,
|
||||
}
|
||||
|
||||
async fn get_git_commit_hash(
|
||||
authed: ApiAuthed,
|
||||
Extension(user_db): Extension<UserDB>,
|
||||
Extension(db): Extension<DB>,
|
||||
Tokened { token }: Tokened,
|
||||
Path((w_id, path)): Path<(String, StripPath)>,
|
||||
Query(query): Query<GitCommitHashQuery>,
|
||||
) -> JsonResult<GitCommitHashResponse> {
|
||||
let path = path.to_path();
|
||||
|
||||
check_scopes(&authed, || format!("resources:read:{}", path))?;
|
||||
|
||||
let git_repo_resource_value = get_resource_value_interpolated_internal(
|
||||
&authed,
|
||||
Some(user_db.clone()),
|
||||
&db,
|
||||
&w_id,
|
||||
path,
|
||||
None,
|
||||
&token,
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| Error::NotAuthorized(format!("Access to resource {} denied: ({e})", path)))?;
|
||||
|
||||
let git_resource: GitRepositoryResource = match git_repo_resource_value {
|
||||
Some(value) => serde_json::from_value(value).map_err(|e| {
|
||||
Error::BadRequest(format!("Invalid git repository resource format: {}", e))
|
||||
})?,
|
||||
None => return Err(Error::NotFound(format!("Resource {} not found", path)).into()),
|
||||
};
|
||||
|
||||
let identities: Vec<String> = query
|
||||
.git_ssh_identity
|
||||
.map(|s| s.split(",").map(|s| s.to_string()).collect())
|
||||
.unwrap_or(vec![]);
|
||||
|
||||
let (git_ssh_cmd, filenames) =
|
||||
get_git_ssh_cmd(&authed, &user_db, &db, &w_id, identities).await?;
|
||||
|
||||
let commit_hash = get_repo_latest_commit_hash(&git_resource, git_ssh_cmd).await;
|
||||
|
||||
delete_paths(&filenames).await;
|
||||
|
||||
Ok(Json(GitCommitHashResponse { commit_hash: commit_hash? }))
|
||||
}
|
||||
|
||||
async fn write_ssh_file(
|
||||
authed: &ApiAuthed,
|
||||
user_db: &UserDB,
|
||||
db: &DB,
|
||||
w_id: &str,
|
||||
var_path: &str,
|
||||
) -> std::result::Result<std::path::PathBuf, (error::Error, std::path::PathBuf)> {
|
||||
let id_file_name = format!(".ssh_id_priv_{}", Uuid::new_v4());
|
||||
let loc = std::path::Path::new(TMP_DIR)
|
||||
.join("ssh_ids")
|
||||
.join(id_file_name);
|
||||
|
||||
let userdb_authed = UserDbWithAuthed { db: user_db.clone(), authed: &authed.to_authed_ref() };
|
||||
let mut content = get_value_internal(&userdb_authed, db, w_id, var_path, authed, false)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
(
|
||||
error::Error::NotFound(format!(
|
||||
"Variable {var_path} not found for git ssh identity: {e:#}"
|
||||
)),
|
||||
loc.clone(),
|
||||
)
|
||||
})?;
|
||||
content.push_str("\n");
|
||||
|
||||
if let Some(p) = &loc.parent() {
|
||||
tokio::fs::create_dir_all(p)
|
||||
.await
|
||||
.map_err(|e| (e.into(), loc.clone()))?;
|
||||
}
|
||||
tokio::fs::write(&loc, content)
|
||||
.await
|
||||
.map_err(|e| (e.into(), loc.clone()))?;
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let perm = std::os::unix::fs::PermissionsExt::from_mode(0o600);
|
||||
tokio::fs::set_permissions(&loc, perm)
|
||||
.await
|
||||
.map_err(|e| (e.into(), loc.clone()))?;
|
||||
}
|
||||
|
||||
return Ok(loc);
|
||||
}
|
||||
|
||||
async fn delete_paths(paths: &Vec<std::path::PathBuf>) {
|
||||
for path in paths {
|
||||
let _ = tokio::fs::remove_file(&path).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_git_ssh_cmd(
|
||||
authed: &ApiAuthed,
|
||||
user_db: &UserDB,
|
||||
db: &DB,
|
||||
w_id: &str,
|
||||
git_ssh_identity: Vec<String>,
|
||||
) -> error::Result<(Option<String>, Vec<std::path::PathBuf>)> {
|
||||
if git_ssh_identity.len() > 5 {
|
||||
return Err(error::Error::BadRequest(
|
||||
"Too many ssh identities, try using at most 1".to_string(),
|
||||
));
|
||||
}
|
||||
if git_ssh_identity.len() == 0 {
|
||||
return Ok((None, vec![]));
|
||||
}
|
||||
|
||||
let mut ssh_id_files = vec![];
|
||||
let mut file_paths = vec![];
|
||||
for var_path in git_ssh_identity.iter() {
|
||||
match write_ssh_file(authed, user_db, db, w_id, &var_path).await {
|
||||
Ok(loc) => {
|
||||
ssh_id_files.push(format!(
|
||||
" -i '{}'",
|
||||
loc.to_string_lossy().replace('\'', r"'\''")
|
||||
));
|
||||
file_paths.push(loc);
|
||||
}
|
||||
Err((e, loc)) => {
|
||||
file_paths.push(loc);
|
||||
delete_paths(&file_paths).await;
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let git_ssh_cmd = format!("ssh -o StrictHostKeyChecking=no{}", ssh_id_files.join(""));
|
||||
Ok((Some(git_ssh_cmd), file_paths))
|
||||
}
|
||||
|
||||
async fn get_repo_latest_commit_hash(
|
||||
git_resource: &GitRepositoryResource,
|
||||
git_ssh_command: Option<String>,
|
||||
) -> Result<String> {
|
||||
let mut git_cmd = Command::new("git");
|
||||
|
||||
let ref_spec = git_resource
|
||||
.branch
|
||||
.as_deref()
|
||||
.filter(|s| !s.is_empty())
|
||||
.unwrap_or("HEAD");
|
||||
|
||||
git_cmd.args(["ls-remote", &git_resource.url, ref_spec]);
|
||||
if let Some(git_ssh_command) = git_ssh_command {
|
||||
git_cmd.env("GIT_SSH_COMMAND", git_ssh_command);
|
||||
}
|
||||
git_cmd.stderr(Stdio::piped());
|
||||
|
||||
let output = git_cmd
|
||||
.output()
|
||||
.await
|
||||
.map_err(|e| Error::internal_err(format!("Failed to execute git command: {}", e)))?;
|
||||
|
||||
if !output.status.success() {
|
||||
let stderr = String::from_utf8(output.stderr)
|
||||
.unwrap_or_else(|_| "Failed to decode stderr".to_string());
|
||||
return Err(Error::BadRequest(format!(
|
||||
"Error getting git repo commit hash: {}",
|
||||
stderr
|
||||
)));
|
||||
}
|
||||
|
||||
let stdout = String::from_utf8(output.stdout)
|
||||
.map_err(|e| Error::internal_err(format!("Failed to decode git output: {}", e)))?;
|
||||
|
||||
let lines: Vec<&str> = stdout.lines().collect();
|
||||
|
||||
if lines.is_empty() {
|
||||
return Err(Error::BadRequest(format!(
|
||||
"No commits found for reference '{}' in repository '{}'",
|
||||
ref_spec, git_resource.url
|
||||
)));
|
||||
}
|
||||
|
||||
let commit_hash = lines
|
||||
.first()
|
||||
.and_then(|line| line.split_whitespace().next())
|
||||
.map(|s| s.to_string())
|
||||
.ok_or_else(|| {
|
||||
Error::BadRequest("Unexpected output format for git ls-remote".to_string())
|
||||
})?;
|
||||
|
||||
Ok(commit_hash)
|
||||
}
|
||||
|
||||
@@ -769,6 +769,14 @@ async fn create_script_internal<'c>(
|
||||
}
|
||||
};
|
||||
|
||||
// Row lock debounce key for path. We need this to make all updates of runnables sequential and predictable.
|
||||
tokio::time::timeout(
|
||||
core::time::Duration::from_secs(60),
|
||||
windmill_common::jobs::lock_debounce_key(&w_id, &ns.path, &mut tx),
|
||||
)
|
||||
.warn_after_seconds(10)
|
||||
.await??;
|
||||
|
||||
sqlx::query!(
|
||||
"INSERT INTO script (workspace_id, hash, path, parent_hashes, summary, description, \
|
||||
content, created_by, schema, is_template, extra_perms, lock, language, kind, tag, \
|
||||
@@ -817,6 +825,7 @@ async fn create_script_internal<'c>(
|
||||
)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
|
||||
let p_path_opt = parent_hashes_and_perms.as_ref().map(|x| x.p_path.clone());
|
||||
if let Some(ref p_path) = p_path_opt {
|
||||
sqlx::query!(
|
||||
@@ -1000,6 +1009,7 @@ async fn create_script_internal<'c>(
|
||||
Some(&authed.clone().into()),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
Ok((hash, new_tx, None))
|
||||
@@ -1249,7 +1259,8 @@ async fn update_script_history(
|
||||
|
||||
let mut tx = user_db.begin(&authed).await?;
|
||||
sqlx::query!(
|
||||
"INSERT INTO deployment_metadata (workspace_id, path, script_hash, deployment_msg) VALUES ($1, $2, $3, $4) ON CONFLICT (workspace_id, script_hash) WHERE script_hash IS NOT NULL DO UPDATE SET deployment_msg = $4",
|
||||
"INSERT INTO deployment_metadata (workspace_id, path, script_hash, deployment_msg) VALUES ($1, $2, $3, $4) ON CONFLICT (workspace_id, script_hash) WHERE script_hash IS NOT NULL
|
||||
DO UPDATE SET deployment_msg = EXCLUDED.deployment_msg",
|
||||
w_id,
|
||||
script_path,
|
||||
script_hash.0,
|
||||
|
||||
@@ -218,6 +218,10 @@ pub struct Value {
|
||||
}
|
||||
|
||||
pub async fn delete_global_setting(db: &DB, key: &str) -> error::Result<()> {
|
||||
if key == "ducklake_user_pg_pwd" || key == "ducklake_settings" {
|
||||
tracing::error!("Tried to unset global setting {}, ignored", key);
|
||||
return Ok(());
|
||||
}
|
||||
sqlx::query!("DELETE FROM global_settings WHERE name = $1", key,)
|
||||
.execute(db)
|
||||
.await?;
|
||||
@@ -334,7 +338,7 @@ pub async fn set_global_setting_internal(
|
||||
}
|
||||
v => {
|
||||
sqlx::query!(
|
||||
"INSERT INTO global_settings (name, value) VALUES ($1, $2) ON CONFLICT (name) DO UPDATE SET value = $2, updated_at = now()",
|
||||
"INSERT INTO global_settings (name, value) VALUES ($1, $2) ON CONFLICT (name) DO UPDATE SET value = EXCLUDED.value, updated_at = now()",
|
||||
key,
|
||||
v
|
||||
)
|
||||
|
||||
@@ -861,6 +861,7 @@ async fn trigger_script_with_retry_and_error_handler(
|
||||
push_authed.as_ref(),
|
||||
false,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
|
||||
@@ -583,7 +583,7 @@ async fn update_tutorial_progress(
|
||||
Json(progress): Json<Progress>,
|
||||
) -> Result<String> {
|
||||
sqlx::query_scalar!(
|
||||
"INSERT INTO tutorial_progress VALUES ($2, $1::bigint::bit(64)) ON CONFLICT (email) DO UPDATE SET progress = $1::bigint::bit(64)",
|
||||
"INSERT INTO tutorial_progress VALUES ($2, $1::bigint::bit(64)) ON CONFLICT (email) DO UPDATE SET progress = EXCLUDED.progress",
|
||||
progress.progress as i64,
|
||||
authed.email
|
||||
)
|
||||
@@ -1385,7 +1385,9 @@ async fn convert_user_to_group(
|
||||
// Check if user is already a group user
|
||||
if let Some(added_via) = &user_info.added_via {
|
||||
if added_via.get("source").and_then(|v| v.as_str()) == Some("instance_group") {
|
||||
return Err(Error::BadRequest("User is already a group user".to_string()));
|
||||
return Err(Error::BadRequest(
|
||||
"User is already a group user".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1408,16 +1410,18 @@ async fn convert_user_to_group(
|
||||
|
||||
if eligible_groups.is_empty() {
|
||||
return Err(Error::BadRequest(
|
||||
"User is not a member of any instance groups configured for auto-add in this workspace".to_string()
|
||||
"User is not a member of any instance groups configured for auto-add in this workspace"
|
||||
.to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
// Determine the group with highest precedence (same logic as process_instance_group_auto_adds)
|
||||
let roles: std::collections::HashMap<String, String> = if let Some(roles_json) = &eligible_groups[0].auto_add_instance_groups_roles {
|
||||
serde_json::from_value(roles_json.clone()).unwrap_or_default()
|
||||
} else {
|
||||
std::collections::HashMap::new()
|
||||
};
|
||||
let roles: std::collections::HashMap<String, String> =
|
||||
if let Some(roles_json) = &eligible_groups[0].auto_add_instance_groups_roles {
|
||||
serde_json::from_value(roles_json.clone()).unwrap_or_default()
|
||||
} else {
|
||||
std::collections::HashMap::new()
|
||||
};
|
||||
|
||||
let mut best_group = &eligible_groups[0].group_name;
|
||||
let mut best_precedence = 0u8;
|
||||
@@ -1443,7 +1447,10 @@ async fn convert_user_to_group(
|
||||
|
||||
// Determine role from group configuration using the selected primary group
|
||||
let default_role = "developer".to_string();
|
||||
let role = roles.get(primary_group_name).unwrap_or(&default_role).as_str();
|
||||
let role = roles
|
||||
.get(primary_group_name)
|
||||
.unwrap_or(&default_role)
|
||||
.as_str();
|
||||
|
||||
let (is_admin, is_operator) = match role {
|
||||
"admin" => (true, false),
|
||||
@@ -1487,12 +1494,18 @@ async fn convert_user_to_group(
|
||||
&db,
|
||||
&w_id,
|
||||
windmill_git_sync::DeployedObject::User { email: user_info.email.clone() },
|
||||
Some(format!("Converted user '{}' to group user (group: {}, role: {})", &user_info.email, primary_group_name, role)),
|
||||
Some(format!(
|
||||
"Converted user '{}' to group user (group: {}, role: {})",
|
||||
&user_info.email, primary_group_name, role
|
||||
)),
|
||||
true,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(format!("User {} converted to group user (group: {}, role: {})", username_to_convert, primary_group_name, role))
|
||||
Ok(format!(
|
||||
"User {} converted to group user (group: {}, role: {})",
|
||||
username_to_convert, primary_group_name, role
|
||||
))
|
||||
}
|
||||
|
||||
async fn update_user(
|
||||
@@ -1594,9 +1607,12 @@ async fn delete_user(
|
||||
}
|
||||
|
||||
// Remove user from all instance groups email_to_igroup
|
||||
sqlx::query!("DELETE FROM email_to_igroup WHERE email = $1", &email_to_delete)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
sqlx::query!(
|
||||
"DELETE FROM email_to_igroup WHERE email = $1",
|
||||
&email_to_delete
|
||||
)
|
||||
.execute(&mut *tx)
|
||||
.await?;
|
||||
|
||||
audit_log(
|
||||
&mut *tx,
|
||||
|
||||
@@ -864,36 +864,3 @@ pub async fn get_value_internal<'a, 'e, A: sqlx::Acquire<'e, Database = Postgres
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
pub async fn get_variable_or_self(path: String, db: &DB, w_id: &str) -> Result<String> {
|
||||
if !path.starts_with("$var:") {
|
||||
return Ok(path);
|
||||
}
|
||||
let path = path.strip_prefix("$var:").unwrap().to_string();
|
||||
|
||||
let record = sqlx::query!(
|
||||
"SELECT value, is_secret
|
||||
FROM variable
|
||||
WHERE path = $1 AND workspace_id = $2",
|
||||
&path,
|
||||
&w_id
|
||||
)
|
||||
.fetch_optional(db)
|
||||
.await?;
|
||||
|
||||
if let Some(record) = record {
|
||||
let mut value = record.value;
|
||||
if record.is_secret {
|
||||
let mc = build_crypt(db, w_id).await?;
|
||||
value = decrypt(&mc, value).map_err(|e| {
|
||||
Error::internal_err(format!("Error decrypting variable {}: {}", path, e))
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(value)
|
||||
} else {
|
||||
Err(Error::NotFound(format!(
|
||||
"Variable not found when resolving `$var:{}`",
|
||||
path
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user