Compare commits

...

65 Commits

Author SHA1 Message Date
Ruben Fiszel
0c391e92a2 improve benchmarks 2025-02-18 09:51:21 +01:00
Ruben Fiszel
588ff79364 make benchmarks even more stable 2025-02-18 08:43:03 +01:00
Ruben Fiszel
3b6585afdf nit benchmarks 2025-02-18 01:54:14 +01:00
Ruben Fiszel
3d7882577f chore(main): release 1.463.4 (#5309)
* chore(main): release 1.463.4

* Update CHANGELOG.md

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-18 00:55:01 +01:00
Ruben Fiszel
9234701f05 ensure index creation of root_job_by_path 2025-02-17 23:57:38 +01:00
Alexander Petric
935b5b7996 fix: improve teams settings in workspace settings (#5316) 2025-02-17 22:44:26 +01:00
Ruben Fiszel
c6b2e6653a output incorrect jobs in benchmarks 2025-02-17 22:20:33 +01:00
Ruben Fiszel
0dd0a795a6 nit benchmarks improvement 2025-02-17 21:54:58 +01:00
Ruben Fiszel
953082681e fix: improve que job indices for faster performances 2025-02-17 21:26:46 +01:00
Ruben Fiszel
e0d7a54a2d nit on bench scripts 2025-02-17 19:26:34 +01:00
Ruben Fiszel
85c56e9450 fix: improve que job indices for faster performances 2025-02-17 19:17:30 +01:00
Ruben Fiszel
5e22690bd9 fix: improve que job indices for faster performances 2025-02-17 17:56:28 +01:00
Ruben Fiszel
fe337293da chore(main): release 1.463.3 (#5308)
* chore(main): release 1.463.3

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-17 15:41:06 +01:00
Ruben Fiszel
0208f53541 fix: windmill_admin has implicit bypass rls on v2_job even if role not set 2025-02-17 15:20:39 +01:00
Ruben Fiszel
3493185e2f nits 2025-02-17 14:34:22 +01:00
Ruben Fiszel
3535016608 improve version detection from source 2025-02-17 11:49:06 +01:00
Ruben Fiszel
449cbcf0c3 chore(main): release 1.463.2 (#5305)
* chore(main): release 1.463.2

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-16 02:07:01 +01:00
Alexander Petric
062e6bc161 fix: show skipped flows as success (#5304) 2025-02-16 02:03:25 +01:00
Ruben Fiszel
cad14c25f6 chore(main): release 1.463.1 (#5303)
* chore(main): release 1.463.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-15 20:44:26 +01:00
pyranota
53f47bcfc8 fix: not able to filter runs by schedule (#5302) 2025-02-15 20:39:37 +01:00
Ruben Fiszel
f1d9922688 chore(main): release 1.463.0 (#5293)
* chore(main): release 1.463.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-14 23:07:39 +01:00
Alexander Petric
8adf02ba3c reactivity fix on teams workspace dropdown (#5300) 2025-02-14 23:07:17 +01:00
Alexander Petric
dad829adf4 feat: adding docker log rotation by default in docker compose (#5295)
* feat: adding docker log rotation by default in docker compose

* add newline

* add compression
2025-02-14 20:48:33 +01:00
HugoCasa
41eecc1437 fix: static website serving (#5298) 2025-02-14 19:03:40 +01:00
Ruben Fiszel
3544e20dca nits 2025-02-14 18:49:26 +01:00
Ruben Fiszel
cfe5232f56 nits 2025-02-14 17:15:59 +01:00
Ruben Fiszel
e0f3e0b1f8 nit 2025-02-14 16:51:49 +01:00
Ruben Fiszel
826fd436bb optimize network calls of flow status 2025-02-14 16:43:58 +01:00
HugoCasa
28558e674f feat: parse script for preprocessor/no_main_func on deploy (#5292)
* feat: parse script for preprocessor/no_main_func on deploy

* fix substitute for linux
2025-02-14 15:42:18 +01:00
Ruben Fiszel
266f82046a fix: improve runs page load time 2025-02-14 13:30:07 +01:00
Ruben Fiszel
7ec4f68dbb chore(main): release 1.462.3 (#5290)
* chore(main): release 1.462.2

* bump
2025-02-14 11:50:12 +01:00
Ruben Fiszel
9ccadb6085 fix: users should be able to see their own jobs 2025-02-14 11:12:26 +01:00
Ruben Fiszel
9c5756507b chore(main): release 1.462.2 (#5286)
* chore(main): release 1.462.2

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-14 04:38:09 +01:00
Ruben Fiszel
77a8eedc96 fix: display branch chosen even if emoty branch 2025-02-14 04:23:25 +01:00
Ruben Fiszel
e7d4582789 fix: improve handling of empty branches and loops 2025-02-14 04:12:55 +01:00
Ruben Fiszel
6f05b7785f chore(main): release 1.462.1 (#5285)
* chore(main): release 1.462.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-14 03:14:52 +01:00
Ruben Fiszel
470d80e219 fix: ai_models in workspace_settings is now optional 2025-02-14 02:45:13 +01:00
Ruben Fiszel
0b4cfd8ffa chore(main): release 1.462.0 (#5281)
* chore(main): release 1.462.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-14 00:28:22 +01:00
Ruben Fiszel
08c784e6c2 improve input history 2025-02-14 00:07:29 +01:00
Ruben Fiszel
586044e077 v2 list jobs 2025-02-13 23:53:00 +01:00
Alexander Petric
2ea3bdec2d fix: populate teams channel on initial load (#5284) 2025-02-13 22:24:48 +01:00
Ruben Fiszel
86d45c61c9 fix extra_perms for schedule light 2025-02-13 21:34:53 +01:00
Ruben Fiszel
a814024440 re-enable RLS on v2_job 2025-02-13 21:04:17 +01:00
Ruben Fiszel
f15b67b4e4 workspace colors fix 2025-02-13 20:23:12 +01:00
Ruben Fiszel
1e45903d78 re-do the migration finalization but now with BYPASSRLS for v2_job_queue and v2_job_completed 2025-02-13 20:03:48 +01:00
Ruben Fiszel
fad6dc4400 Revert "revert last commit"
This reverts commit b6a57207a2.
2025-02-13 19:45:52 +01:00
Ruben Fiszel
b6a57207a2 revert last commit 2025-02-13 19:38:58 +01:00
Ruben Fiszel
9a5fe90bdd Revert "migration to remove unecessary triggers and fields after job v2"
This reverts commit 029e2c7537.
2025-02-13 19:37:45 +01:00
Ruben Fiszel
029e2c7537 migration to remove unecessary triggers and fields after job v2 2025-02-13 19:18:32 +01:00
Ruben Fiszel
4fa897fbb6 remove v5 migration 2025-02-13 17:51:03 +01:00
Lucas Abel
b1f358d4a2 backend: finalize v2 migration (v2 phase 4 - final) (#5155)
* backend: finalize v2 migration (v2 phase 4 - final)

* update migration

---------

Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2025-02-13 17:10:30 +01:00
Alexander Petric
149d5fb3e1 feat: teams workspace scripts (#5238)
* backend and clients

* adding teams_team_name to workspace_settings

* openapi.yaml adding teams workspace settings endpoints

* teams workspace settings frontend

* workspaces router

* build ce

* ee gate

* ee oauth

* update client

* workspace error handler

* remove log

* ce

* point to new hub scripts

* updating hubPaths

* updating hubPaths

* cleanup

* merge

* schedule teams error

* polish, reactivity

* sqlx compilewarning

* sqlx migrate

* make it build

* router

* fix

* remove sqlx workaround

* Update ee-repo-ref.txt

* simplify some logic

* sqlx

* latest ee ref

* latest ee ref

---------

Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2025-02-13 16:53:57 +01:00
Ruben Fiszel
1be335f042 fix(bun): remove unecessary buntar in a bun bundle world 2025-02-13 13:40:44 +01:00
Ruben Fiszel
dd695b40f4 fix(cli): support lock in wmill dev 2025-02-13 13:02:36 +01:00
Henri Courdent
69ed5a9bbf List of telemetry collected (#5282) 2025-02-13 12:18:39 +01:00
Ruben Fiszel
fe922114a7 fix(bun): remove unecessary buntar in a bun bundle world 2025-02-13 10:27:48 +01:00
Ruben Fiszel
768c11310f chore(main): release 1.461.1 (#5278)
* chore(main): release 1.461.1

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-13 01:54:48 +01:00
Ruben Fiszel
6fb8f7b45d fix(cli): fix nits preventing release 2025-02-13 01:51:54 +01:00
Ruben Fiszel
97c64b3dc2 chore(main): release 1.461.0 (#5276)
* chore(main): release 1.461.0

* Apply automatic changes

---------

Co-authored-by: rubenfiszel <275584+rubenfiszel@users.noreply.github.com>
2025-02-13 01:41:05 +01:00
Ruben Fiszel
8895f05375 add button work for flows 2025-02-13 01:34:37 +01:00
Ruben Fiszel
956a5ac682 feat(cli): wmill dev works with flows 2025-02-13 01:25:18 +01:00
Ruben Fiszel
055c3367b7 fix: remove variable pickers in app forms 2025-02-12 23:38:58 +01:00
Ruben Fiszel
2015e79ff0 fix: better handling of null pre-processor return values 2025-02-12 22:10:53 +01:00
Ruben Fiszel
fcbfef4c31 fix encrypted values passed from apps in flows 2025-02-12 20:07:27 +01:00
Lucas Abel
bf206515e8 fix(backend): improve schedule queries plan to leverage indices better for performance (#5273)
* backend: fix schedule queries plan

* rework

* fix skipped as non success

* update sqlx

* update

* all

* fix npm run check

---------

Co-authored-by: Ruben Fiszel <ruben@windmill.dev>
2025-02-12 16:34:03 +01:00
145 changed files with 3076 additions and 2543 deletions

4
.env
View File

@@ -7,3 +7,7 @@ WM_IMAGE=ghcr.io/windmill-labs/windmill:main
# To use another port than :80, setup the Caddyfile and the caddy section of the docker-compose to your needs: https://caddyserver.com/docs/getting-started
# To have caddy take care of automatic TLS
# To rotate logs, set the following variables:
#LOG_MAX_SIZE=10m
#LOG_MAX_FILE=3

View File

@@ -162,6 +162,7 @@ jobs:
-c
https://raw.githubusercontent.com/windmill-labs/windmill/${GITHUB_REF##ref/head/}/benchmarks/suite_config.json
--workers 4
--factor 3
- name: Save benchmark results
uses: actions/upload-artifact@v4
with:
@@ -281,6 +282,7 @@ jobs:
-c
https://raw.githubusercontent.com/windmill-labs/windmill/${GITHUB_REF##ref/head/}/benchmarks/suite_config.json
--workers 8
--factor 3
- name: Save benchmark results
uses: actions/upload-artifact@v4
with:

View File

@@ -1,5 +1,109 @@
# Changelog
## [1.463.4](https://github.com/windmill-labs/windmill/compare/v1.463.3...v1.463.4) (2025-02-17)
### Bug Fixes
* improve queue job indices for faster performances ([9530826](https://github.com/windmill-labs/windmill/commit/953082681e2c4fd71d5ac1acf372265ccc72297b))
* improve teams settings in workspace settings ([#5316](https://github.com/windmill-labs/windmill/issues/5316)) ([935b5b7](https://github.com/windmill-labs/windmill/commit/935b5b799636c0f02597315837268d4a76f6709a))
## [1.463.3](https://github.com/windmill-labs/windmill/compare/v1.463.2...v1.463.3) (2025-02-17)
### Bug Fixes
* windmill_admin has implicit bypass rls on v2_job even if role not set ([0208f53](https://github.com/windmill-labs/windmill/commit/0208f53541473aa51bed0e15d938def3d4530e3f))
## [1.463.2](https://github.com/windmill-labs/windmill/compare/v1.463.1...v1.463.2) (2025-02-16)
### Bug Fixes
* show skipped flows as success ([#5304](https://github.com/windmill-labs/windmill/issues/5304)) ([062e6bc](https://github.com/windmill-labs/windmill/commit/062e6bc161b56215cb081209d37ad8e0cbd1dd99))
## [1.463.1](https://github.com/windmill-labs/windmill/compare/v1.463.0...v1.463.1) (2025-02-15)
### Bug Fixes
* not able to filter runs by schedule ([#5302](https://github.com/windmill-labs/windmill/issues/5302)) ([53f47bc](https://github.com/windmill-labs/windmill/commit/53f47bcfc84ed747b55d3a7d84ccf13ff1c43c97))
## [1.463.0](https://github.com/windmill-labs/windmill/compare/v1.462.1...v1.463.0) (2025-02-14)
### Features
* adding docker log rotation by default in docker compose ([#5295](https://github.com/windmill-labs/windmill/issues/5295)) ([dad829a](https://github.com/windmill-labs/windmill/commit/dad829adf4bff97e998f7d18e0bbafb8497d4198))
* parse script for preprocessor/no_main_func on deploy ([#5292](https://github.com/windmill-labs/windmill/issues/5292)) ([28558e6](https://github.com/windmill-labs/windmill/commit/28558e674f60fef1b165a79c039b1b450759d500))
### Bug Fixes
* display branch chosen even if emoty branch ([77a8eed](https://github.com/windmill-labs/windmill/commit/77a8eedc96171e9f84463407bdc5aec9b7b10d62))
* improve handling of empty branches and loops ([e7d4582](https://github.com/windmill-labs/windmill/commit/e7d458278969897aa7312dcd20a8091aaad772d7))
* improve runs page load time ([266f820](https://github.com/windmill-labs/windmill/commit/266f82046ad287163d24910902393cd63156ca1d))
* static website serving ([#5298](https://github.com/windmill-labs/windmill/issues/5298)) ([41eecc1](https://github.com/windmill-labs/windmill/commit/41eecc1437301bea557fb467cc48b502162de419))
* users should be able to see their own jobs ([9ccadb6](https://github.com/windmill-labs/windmill/commit/9ccadb6085498119bdfcc172d52c7fce1eb3336e))
## [1.462.3](https://github.com/windmill-labs/windmill/compare/v1.462.1...v1.462.2) (2025-02-14)
### Bug Fixes
* users should be able to see their own jobs ([9ccadb6](https://github.com/windmill-labs/windmill/commit/9ccadb6085498119bdfcc172d52c7fce1eb3336e))
## [1.462.2](https://github.com/windmill-labs/windmill/compare/v1.462.1...v1.462.2) (2025-02-14)
### Bug Fixes
* display branch chosen even if emoty branch ([77a8eed](https://github.com/windmill-labs/windmill/commit/77a8eedc96171e9f84463407bdc5aec9b7b10d62))
* improve handling of empty branches and loops ([e7d4582](https://github.com/windmill-labs/windmill/commit/e7d458278969897aa7312dcd20a8091aaad772d7))
## [1.462.1](https://github.com/windmill-labs/windmill/compare/v1.462.0...v1.462.1) (2025-02-14)
### Bug Fixes
* ai_models in workspace_settings is now optional ([470d80e](https://github.com/windmill-labs/windmill/commit/470d80e219f3b8a3fc3f56802d0eaeffbb1d415f))
## [1.462.0](https://github.com/windmill-labs/windmill/compare/v1.461.1...v1.462.0) (2025-02-13)
### Features
* teams workspace scripts ([#5238](https://github.com/windmill-labs/windmill/issues/5238)) ([149d5fb](https://github.com/windmill-labs/windmill/commit/149d5fb3e1d7c89a6005aa34ef34fa57657f507b))
### Bug Fixes
* **bun:** remove unecessary buntar in a bun bundle world ([1be335f](https://github.com/windmill-labs/windmill/commit/1be335f042727bbb33b5f515433b65c54bf841fe))
* **bun:** remove unecessary buntar in a bun bundle world ([fe92211](https://github.com/windmill-labs/windmill/commit/fe922114a74b1757c37f7f7b76adb3aed1ffccc4))
* **cli:** support lock in wmill dev ([dd695b4](https://github.com/windmill-labs/windmill/commit/dd695b40f41decdf9f2f3d6918d860249661fb36))
* populate teams channel on initial load ([#5284](https://github.com/windmill-labs/windmill/issues/5284)) ([2ea3bde](https://github.com/windmill-labs/windmill/commit/2ea3bdec2d7a65f8ceeea84f9e677fb4d2c5e0f3))
## [1.461.1](https://github.com/windmill-labs/windmill/compare/v1.461.0...v1.461.1) (2025-02-13)
### Bug Fixes
* **cli:** fix nits preventing release ([6fb8f7b](https://github.com/windmill-labs/windmill/commit/6fb8f7b45dd85fdf5edc5ca3948f767eb0a39629))
## [1.461.0](https://github.com/windmill-labs/windmill/compare/v1.460.1...v1.461.0) (2025-02-13)
### Features
* **cli:** wmill dev works with flows ([956a5ac](https://github.com/windmill-labs/windmill/commit/956a5ac68236df1c1f9ea4facd7ad237457427cf))
### Bug Fixes
* **backend:** improve schedule queries plan to leverage indices better for performance ([#5273](https://github.com/windmill-labs/windmill/issues/5273)) ([bf20651](https://github.com/windmill-labs/windmill/commit/bf206515e8653bbe431e106277b72082e0c9e388))
* better handling of null pre-processor return values ([2015e79](https://github.com/windmill-labs/windmill/commit/2015e79ff09293cafb799f4049de35f786059831))
* remove variable pickers in app forms ([055c336](https://github.com/windmill-labs/windmill/commit/055c3367b7afd06a9c789d17fb29bf1d195055bc))
## [1.460.1](https://github.com/windmill-labs/windmill/compare/v1.460.0...v1.460.1) (2025-02-12)

View File

@@ -1,24 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE postgres_trigger \n SET \n server_id = $1, \n last_server_ping = now(),\n error = 'Connecting...'\n WHERE \n enabled IS TRUE \n AND workspace_id = $2 \n AND path = $3 \n AND (last_server_ping IS NULL \n OR last_server_ping < now() - INTERVAL '15 seconds'\n ) \n RETURNING true\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Varchar",
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "01e92a4ba3074f1dce6ec98bc6c3fad4878f48db8c17c6d58590bd5df2e3350a"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT * FROM workspace_settings WHERE workspace_id = $1",
"query": "SELECT * FROM workspace_settings WHERE teams_team_id = $1 AND teams_command_script IS NOT NULL",
"describe": {
"columns": [
{
@@ -130,11 +130,26 @@
},
{
"ordinal": 25,
"name": "teams_command_script",
"type_info": "Text"
},
{
"ordinal": 26,
"name": "teams_team_id",
"type_info": "Text"
},
{
"ordinal": 27,
"name": "teams_team_name",
"type_info": "Text"
},
{
"ordinal": 28,
"name": "ai_models",
"type_info": "VarcharArray"
},
{
"ordinal": 26,
"ordinal": 29,
"name": "code_completion_model",
"type_info": "Varchar"
}
@@ -170,9 +185,12 @@
true,
true,
true,
true,
true,
true,
false,
true
]
},
"hash": "1730f39fd1793d45fbb41b21389c61296a3ff7489ae12f52a19f9543173ac597"
"hash": "08f288d2781d823e109a9e5b8848234ca7d1efeee9661f3901f298da375e73f7"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT coalesce(COUNT(*) FILTER(WHERE suspend = 0 AND running = false), 0) as \"database_length!\", coalesce(COUNT(*) FILTER(WHERE suspend > 0), 0) as \"suspended!\" FROM v2_as_queue WHERE (workspace_id = $1 OR $2) AND scheduled_for <= now()",
"query": "SELECT coalesce(COUNT(*) FILTER(WHERE suspend = 0 AND running = false), 0) as \"database_length!\", coalesce(COUNT(*) FILTER(WHERE suspend > 0), 0) as \"suspended!\" FROM v2_as_queue WHERE (workspace_id = $1 OR $2) AND scheduled_for <= now() AND ($3::text[] IS NULL OR tag = ANY($3))",
"describe": {
"columns": [
{
@@ -17,7 +17,8 @@
"parameters": {
"Left": [
"Text",
"Bool"
"Bool",
"TextArray"
]
},
"nullable": [
@@ -25,5 +26,5 @@
null
]
},
"hash": "19cc8499f682ec34d54bc4f694cb281a9bd7f5431c646c6268513751fff95395"
"hash": "0cb0e912bc942af2b1ef784455f3f073a79e300f3dd48f14122d1782eee663cd"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "DROP INDEX CONCURRENTLY IF EXISTS queue_sort",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "0efb16cbf130ec6e9922ecc82a95b252449bd569df374e40ce8820fc3d75a0f0"
}

View File

@@ -1,40 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT\n schemaname AS schema_name,\n tablename AS table_name,\n attnames AS columns,\n rowfilter AS where_clause\n FROM\n pg_publication_tables\n WHERE\n pubname = $1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "schema_name",
"type_info": "Name"
},
{
"ordinal": 1,
"name": "table_name",
"type_info": "Name"
},
{
"ordinal": 2,
"name": "columns",
"type_info": "NameArray"
},
{
"ordinal": 3,
"name": "where_clause",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Name"
]
},
"nullable": [
true,
true,
true,
true
]
},
"hash": "199a76c04e3f0891ad09af27b9534bbabdd8703bfdf4d43df2c65e50d4ca2c85"
}

View File

@@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "SELECT teams_team_id FROM workspace_settings WHERE workspace_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "teams_team_id",
"type_info": "Text"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
true
]
},
"hash": "1ace9bdcde90fd2261fd64344a2d9474b17887711128dbb2ef15d247d50686b0"
}

View File

@@ -0,0 +1,14 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE workspace_settings\n SET teams_team_id = null, teams_team_name = null WHERE workspace_id = $1",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text"
]
},
"nullable": []
},
"hash": "23c37d36e16251763fabf194e41de63612a7506cc0671b0eb83e528c1c839db4"
}

View File

@@ -0,0 +1,24 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE v2_job_status\n SET flow_status = JSONB_SET(flow_status, ARRAY['modules', $1::TEXT], $2)\n WHERE id = $3\n RETURNING flow_status AS \"flow_status: Json<Box<RawValue>>\"",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "flow_status: Json<Box<RawValue>>",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": [
"Text",
"Jsonb",
"Uuid"
]
},
"nullable": [
true
]
},
"hash": "30216cf02e972f961b7cc6054050fdc984be118df1ad68f7263c84e058bb1266"
}

View File

@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "WITH job_result AS (\n SELECT result \n FROM v2_job_completed \n WHERE id = $1\n )\n UPDATE v2_job \n SET args = COALESCE(\n CASE \n WHEN job_result.result IS NULL THEN NULL\n WHEN jsonb_typeof(job_result.result) = 'object' \n THEN job_result.result\n WHEN jsonb_typeof(job_result.result) = 'null'\n THEN NULL\n ELSE jsonb_build_object('value', job_result.result)\n END, \n '{}'::jsonb\n ),\n preprocessed = TRUE\n FROM job_result\n WHERE v2_job.id = $2;\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": []
},
"hash": "303c7e92ce23dc367d97d813415cd9aef958c15df1c0a7b02318a756cd3589e9"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "DROP INDEX CONCURRENTLY IF EXISTS queue_sort_2",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "3738096c29ab9d964be8a74bfd14ff1d599049ebefdaf97a017c9cef8d52ce20"
}

View File

@@ -0,0 +1,25 @@
{
"db_name": "PostgreSQL",
"query": "SELECT EXISTS (\n SELECT 1 FROM v2_job j JOIN v2_job_queue USING (id)\n WHERE j.workspace_id = $1 AND trigger_kind = 'schedule' AND trigger = $2 AND runnable_path = $4\n AND parent_job IS NULL\n AND scheduled_for = $3\n )",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "exists",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Timestamptz",
"Text"
]
},
"nullable": [
null
]
},
"hash": "3a47d8ec0f4ba1644951f0c88504c9f769ffe5004871a049e4232e0092532062"
}

View File

@@ -0,0 +1,22 @@
{
"db_name": "PostgreSQL",
"query": "\n SELECT EXISTS (SELECT 1\n FROM workspace_settings\n WHERE workspace_id <> $1\n AND teams_command_script IS NOT NULL\n AND teams_team_id IS NOT NULL\n AND teams_team_id = (SELECT teams_team_id FROM workspace_settings WHERE workspace_id = $1))\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "exists",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
null
]
},
"hash": "3b02f3ec6b92706c26065b2fa703cd1a1d6eca4083286c6f29c9acba522d2fe3"
}

View File

@@ -1,12 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "create index concurrently if not exists root_job_index_by_path_2 ON v2_job (workspace_id, runnable_path, created_at desc) WHERE parent_job IS NULL",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "3bacf9cd9aa63f4bec5f983f4a0c3030216b5a4ed669f77962509d1c2c6cb780"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "CREATE INDEX CONCURRENTLY queue_sort_v2 ON v2_job_queue (priority DESC NULLS LAST, scheduled_for, tag) WHERE running = false",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "3bbde0fa35d935ec2dd8bd1fb14cfecf48305f5f4b644b3c35355074e1ccce28"
}

View File

@@ -1,118 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT workspace_id, path, url, script_path, is_flow, edited_by, email, edited_at, server_id, last_server_ping, extra_perms, error, enabled, filters as \"filters: _\", initial_messages as \"initial_messages: _\", url_runnable_args as \"url_runnable_args: _\", can_return_message FROM websocket_trigger\n WHERE workspace_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "path",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "url",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "script_path",
"type_info": "Varchar"
},
{
"ordinal": 4,
"name": "is_flow",
"type_info": "Bool"
},
{
"ordinal": 5,
"name": "edited_by",
"type_info": "Varchar"
},
{
"ordinal": 6,
"name": "email",
"type_info": "Varchar"
},
{
"ordinal": 7,
"name": "edited_at",
"type_info": "Timestamptz"
},
{
"ordinal": 8,
"name": "server_id",
"type_info": "Varchar"
},
{
"ordinal": 9,
"name": "last_server_ping",
"type_info": "Timestamptz"
},
{
"ordinal": 10,
"name": "extra_perms",
"type_info": "Jsonb"
},
{
"ordinal": 11,
"name": "error",
"type_info": "Text"
},
{
"ordinal": 12,
"name": "enabled",
"type_info": "Bool"
},
{
"ordinal": 13,
"name": "filters: _",
"type_info": "JsonbArray"
},
{
"ordinal": 14,
"name": "initial_messages: _",
"type_info": "JsonbArray"
},
{
"ordinal": 15,
"name": "url_runnable_args: _",
"type_info": "Jsonb"
},
{
"ordinal": 16,
"name": "can_return_message",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
false,
false,
false,
false,
false,
false,
true,
true,
false,
true,
false,
false,
true,
true,
false
]
},
"hash": "3d0f036a3176dcc787bef3f10a336c93f43dec5df570f869580056702b7d1e09"
}

View File

@@ -0,0 +1,30 @@
{
"db_name": "PostgreSQL",
"query": "SELECT\n schedule.path, t.jobs FROM schedule,\n LATERAL(SELECT ARRAY(\n SELECT json_build_object('id', id, 'success', status = 'success', 'duration_ms', duration_ms)\n FROM v2_job_completed c JOIN v2_job j USING (id)\n WHERE trigger_kind = 'schedule'\n AND trigger = schedule.path\n AND c.workspace_id = $1\n AND j.workspace_id = $1\n AND parent_job IS NULL AND runnable_path = schedule.script_path\n AND status <> 'skipped'\n ORDER BY created_at DESC\n LIMIT 20\n ) AS jobs) t\n WHERE workspace_id = $1\n ORDER BY edited_at DESC\n LIMIT $2 OFFSET $3",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "path",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "jobs",
"type_info": "JsonArray"
}
],
"parameters": {
"Left": [
"Text",
"Int8",
"Int8"
]
},
"nullable": [
false,
null
]
},
"hash": "430ea56dea72c7d326735952bf85708dcc4811857b7e5631f0decf5d75ef3aa3"
}

View File

@@ -1,119 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT workspace_id, path, route_path, route_path_key, script_path, is_flow, edited_by, edited_at, email, extra_perms, is_async, requires_auth, http_method as \"http_method: _\", static_asset_config as \"static_asset_config: _\", is_static_website FROM http_trigger\n WHERE workspace_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "path",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "route_path",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "route_path_key",
"type_info": "Varchar"
},
{
"ordinal": 4,
"name": "script_path",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "is_flow",
"type_info": "Bool"
},
{
"ordinal": 6,
"name": "edited_by",
"type_info": "Varchar"
},
{
"ordinal": 7,
"name": "edited_at",
"type_info": "Timestamptz"
},
{
"ordinal": 8,
"name": "email",
"type_info": "Varchar"
},
{
"ordinal": 9,
"name": "extra_perms",
"type_info": "Jsonb"
},
{
"ordinal": 10,
"name": "is_async",
"type_info": "Bool"
},
{
"ordinal": 11,
"name": "requires_auth",
"type_info": "Bool"
},
{
"ordinal": 12,
"name": "http_method: _",
"type_info": {
"Custom": {
"name": "http_method",
"kind": {
"Enum": [
"get",
"post",
"put",
"delete",
"patch"
]
}
}
}
},
{
"ordinal": 13,
"name": "static_asset_config: _",
"type_info": "Jsonb"
},
{
"ordinal": 14,
"name": "is_static_website",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
false
]
},
"hash": "4331bb1a3559f56c1ee91916b7f15251f0b32afa2445401170d931e0fe1febb8"
}

View File

@@ -1,12 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "VACUUM (skip_locked) v2_job_queue, v2_job_runtime, v2_job_status",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "47455b0ebaf999ab58b2cba3d74cb4bdd64075939a4aa2c117e18372511ea7e0"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "DROP INDEX CONCURRENTLY IF EXISTS ix_job_workspace_id_created_at_new_7",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "4d4aa16b2a55e57f9376d0cb253e671525969fb5f528ae07576e9dc5e77af1f1"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "SELECT schedule.*, t.jobs FROM schedule, LATERAL ( SELECT ARRAY (SELECT json_build_object('id', id, 'success', success, 'duration_ms', duration_ms) FROM v2_as_completed_job WHERE\n v2_as_completed_job.schedule_path = schedule.path AND v2_as_completed_job.workspace_id = $1 AND parent_job IS NULL AND is_skipped = False ORDER BY started_at DESC LIMIT 20) AS jobs ) t\n WHERE schedule.workspace_id = $1 ORDER BY schedule.edited_at desc LIMIT $2 OFFSET $3",
"query": "SELECT workspace_id, slack_team_id, teams_team_id, teams_team_name, slack_name, slack_command_script, teams_command_script, slack_email, auto_invite_domain, auto_invite_operator, auto_add, customer_id, plan, webhook, deploy_to, ai_resource, ai_models, code_completion_model, error_handler, error_handler_extra_args, error_handler_muted_on_cancel, large_file_storage, git_sync, deploy_ui, default_app, automatic_billing, default_scripts, mute_critical_alerts, color, operator_settings FROM workspace_settings WHERE workspace_id = $1",
"describe": {
"columns": [
{
@@ -10,171 +10,165 @@
},
{
"ordinal": 1,
"name": "path",
"name": "slack_team_id",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "edited_by",
"type_info": "Varchar"
"name": "teams_team_id",
"type_info": "Text"
},
{
"ordinal": 3,
"name": "edited_at",
"type_info": "Timestamptz"
"name": "teams_team_name",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "schedule",
"name": "slack_name",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "enabled",
"type_info": "Bool"
},
{
"ordinal": 6,
"name": "script_path",
"name": "slack_command_script",
"type_info": "Varchar"
},
{
"ordinal": 6,
"name": "teams_command_script",
"type_info": "Text"
},
{
"ordinal": 7,
"name": "args",
"type_info": "Jsonb"
"name": "slack_email",
"type_info": "Varchar"
},
{
"ordinal": 8,
"name": "extra_perms",
"type_info": "Jsonb"
"name": "auto_invite_domain",
"type_info": "Varchar"
},
{
"ordinal": 9,
"name": "is_flow",
"name": "auto_invite_operator",
"type_info": "Bool"
},
{
"ordinal": 10,
"name": "email",
"type_info": "Varchar"
"name": "auto_add",
"type_info": "Bool"
},
{
"ordinal": 11,
"name": "error",
"type_info": "Text"
"name": "customer_id",
"type_info": "Varchar"
},
{
"ordinal": 12,
"name": "timezone",
"name": "plan",
"type_info": "Varchar"
},
{
"ordinal": 13,
"name": "on_failure",
"type_info": "Varchar"
"name": "webhook",
"type_info": "Text"
},
{
"ordinal": 14,
"name": "on_recovery",
"name": "deploy_to",
"type_info": "Varchar"
},
{
"ordinal": 15,
"name": "on_failure_times",
"type_info": "Int4"
"name": "ai_resource",
"type_info": "Jsonb"
},
{
"ordinal": 16,
"name": "on_failure_exact",
"type_info": "Bool"
"name": "ai_models",
"type_info": "VarcharArray"
},
{
"ordinal": 17,
"name": "on_failure_extra_args",
"type_info": "Json"
"name": "code_completion_model",
"type_info": "Varchar"
},
{
"ordinal": 18,
"name": "on_recovery_times",
"type_info": "Int4"
"name": "error_handler",
"type_info": "Varchar"
},
{
"ordinal": 19,
"name": "on_recovery_extra_args",
"name": "error_handler_extra_args",
"type_info": "Json"
},
{
"ordinal": 20,
"name": "ws_error_handler_muted",
"name": "error_handler_muted_on_cancel",
"type_info": "Bool"
},
{
"ordinal": 21,
"name": "retry",
"name": "large_file_storage",
"type_info": "Jsonb"
},
{
"ordinal": 22,
"name": "summary",
"type_info": "Varchar"
"name": "git_sync",
"type_info": "Jsonb"
},
{
"ordinal": 23,
"name": "no_flow_overlap",
"type_info": "Bool"
"name": "deploy_ui",
"type_info": "Jsonb"
},
{
"ordinal": 24,
"name": "tag",
"name": "default_app",
"type_info": "Varchar"
},
{
"ordinal": 25,
"name": "paused_until",
"type_info": "Timestamptz"
"name": "automatic_billing",
"type_info": "Bool"
},
{
"ordinal": 26,
"name": "on_success",
"type_info": "Varchar"
"name": "default_scripts",
"type_info": "Jsonb"
},
{
"ordinal": 27,
"name": "on_success_extra_args",
"type_info": "Json"
"name": "mute_critical_alerts",
"type_info": "Bool"
},
{
"ordinal": 28,
"name": "cron_version",
"type_info": "Text"
"name": "color",
"type_info": "Varchar"
},
{
"ordinal": 29,
"name": "jobs",
"type_info": "JsonArray"
"name": "operator_settings",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": [
"Text",
"Int8",
"Int8"
"Text"
]
},
"nullable": [
false,
false,
false,
false,
false,
false,
false,
true,
true,
true,
true,
true,
true,
false,
false,
false,
true,
false,
true,
true,
true,
@@ -185,14 +179,18 @@
false,
true,
true,
true,
false,
true,
true,
true,
true,
false,
true,
null
true,
true,
true
]
},
"hash": "099894523449a70eb301ecd1d744210d39f405016ffec374e4b15a2528baccb5"
"hash": "4e9c2e0690eaca280ccb5e5160438f207d930d29e3000b9845eef89e87a35ad1"
}

View File

@@ -0,0 +1,26 @@
{
"db_name": "PostgreSQL",
"query": "\n WITH assigned_teams AS (\n SELECT teams_team_id\n FROM workspace_settings\n ),\n all_teams AS (\n SELECT jsonb_array_elements(CASE\n WHEN jsonb_typeof(value::jsonb) = 'array' THEN value::jsonb\n ELSE '[]'::jsonb\n END) AS team\n FROM global_settings\n WHERE name = 'teams'\n )\n SELECT team->>'team_name' AS team_name, team->>'team_internal_id' AS team_id\n FROM all_teams\n WHERE NOT EXISTS (\n SELECT 1\n FROM assigned_teams\n WHERE assigned_teams.teams_team_id = team->>'team_internal_id'\n )\n AND team->>'team_name' IS NOT NULL\n AND team->>'team_id' IS NOT NULL\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "team_name",
"type_info": "Text"
},
{
"ordinal": 1,
"name": "team_id",
"type_info": "Text"
}
],
"parameters": {
"Left": []
},
"nullable": [
null,
null
]
},
"hash": "50c17c7848760aaf0f869acfc444caecda6335eda5b2e97e5a7370361653ff48"
}

View File

@@ -0,0 +1,16 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE workspace_settings\n SET teams_team_id = $1, teams_team_name = $2\n WHERE workspace_id = $3\n AND NOT EXISTS (\n SELECT 1 FROM workspace_settings\n WHERE teams_team_id = $1 AND workspace_id <> $2\n )\n ",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "551c78392919e18019bb0a4344fb1bd45853bf5b72e0ab991e0e61fedcfb42fc"
}

View File

@@ -130,11 +130,26 @@
},
{
"ordinal": 25,
"name": "teams_command_script",
"type_info": "Text"
},
{
"ordinal": 26,
"name": "teams_team_id",
"type_info": "Text"
},
{
"ordinal": 27,
"name": "teams_team_name",
"type_info": "Text"
},
{
"ordinal": 28,
"name": "ai_models",
"type_info": "VarcharArray"
},
{
"ordinal": 26,
"ordinal": 29,
"name": "code_completion_model",
"type_info": "Varchar"
}
@@ -170,6 +185,9 @@
true,
true,
true,
true,
true,
true,
false,
true
]

View File

@@ -1,118 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT * FROM nats_trigger\n WHERE workspace_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "path",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "nats_resource_path",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "subjects",
"type_info": "VarcharArray"
},
{
"ordinal": 3,
"name": "stream_name",
"type_info": "Varchar"
},
{
"ordinal": 4,
"name": "consumer_name",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "use_jetstream",
"type_info": "Bool"
},
{
"ordinal": 6,
"name": "script_path",
"type_info": "Varchar"
},
{
"ordinal": 7,
"name": "is_flow",
"type_info": "Bool"
},
{
"ordinal": 8,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 9,
"name": "edited_by",
"type_info": "Varchar"
},
{
"ordinal": 10,
"name": "email",
"type_info": "Varchar"
},
{
"ordinal": 11,
"name": "edited_at",
"type_info": "Timestamptz"
},
{
"ordinal": 12,
"name": "extra_perms",
"type_info": "Jsonb"
},
{
"ordinal": 13,
"name": "server_id",
"type_info": "Varchar"
},
{
"ordinal": 14,
"name": "last_server_ping",
"type_info": "Timestamptz"
},
{
"ordinal": 15,
"name": "error",
"type_info": "Text"
},
{
"ordinal": 16,
"name": "enabled",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
false,
true,
true,
false,
false,
false,
false,
false,
false,
false,
false,
true,
true,
true,
false
]
},
"hash": "59368ac2d4e0918c7ee4275a0b1e3935e9d57be68a1811ffdee904a5f56e7023"
}

View File

@@ -0,0 +1,25 @@
{
"db_name": "PostgreSQL",
"query": "SELECT id\n FROM v2_job j JOIN v2_job_queue USING (id)\n WHERE j.workspace_id = $2 AND trigger_kind = 'schedule' AND trigger = $1 AND runnable_path = $4\n AND parent_job IS NULL\n AND j.id != $3\n AND running = true",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Uuid",
"Text"
]
},
"nullable": [
false
]
},
"hash": "6513c1433dbfe03f7c778963a05d964fda13a1091a8206ee174ed3a161248126"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "DROP INDEX CONCURRENTLY IF EXISTS root_job_index_by_path_2",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "6536214f31e9d600e868b01385d8c6395e2440ea27553b7ccb18d7149b106728"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE workspace_settings\n SET teams_command_script = NULL,\n teams_team_id = NULL,\n teams_team_name = NULL\n ",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "65c339164e7669360d231d70105849e72bdc197c17c0fc51777c1dc9267e2daf"
}

View File

@@ -1,106 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT * FROM postgres_trigger\n WHERE workspace_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "path",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "script_path",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "is_flow",
"type_info": "Bool"
},
{
"ordinal": 3,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 4,
"name": "edited_by",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "email",
"type_info": "Varchar"
},
{
"ordinal": 6,
"name": "edited_at",
"type_info": "Timestamptz"
},
{
"ordinal": 7,
"name": "extra_perms",
"type_info": "Jsonb"
},
{
"ordinal": 8,
"name": "postgres_resource_path",
"type_info": "Varchar"
},
{
"ordinal": 9,
"name": "error",
"type_info": "Text"
},
{
"ordinal": 10,
"name": "server_id",
"type_info": "Varchar"
},
{
"ordinal": 11,
"name": "last_server_ping",
"type_info": "Timestamptz"
},
{
"ordinal": 12,
"name": "replication_slot_name",
"type_info": "Varchar"
},
{
"ordinal": 13,
"name": "publication_name",
"type_info": "Varchar"
},
{
"ordinal": 14,
"name": "enabled",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
false,
false,
false,
false,
false,
true,
false,
true,
true,
true,
false,
false,
false
]
},
"hash": "7f6649b177f4ec948e396e179ea044812f8103498080a24246063e06b0ebfccf"
}

View File

@@ -1,38 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT\n success AS \"success!\",\n result AS \"result: Json<Box<RawValue>>\",\n started_at AS \"started_at!\"FROM v2_as_completed_job WHERE workspace_id = $1 AND schedule_path = $2 AND script_path = $3 AND id != $4\n ORDER BY created_at DESC\n LIMIT $5",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "success!",
"type_info": "Bool"
},
{
"ordinal": 1,
"name": "result: Json<Box<RawValue>>",
"type_info": "Jsonb"
},
{
"ordinal": 2,
"name": "started_at!",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Text",
"Uuid",
"Int8"
]
},
"nullable": [
true,
true,
true
]
},
"hash": "830297547ea33969f96a5c4c2b82a540f1d147948e1b1a7523b21151ffa22305"
}

View File

@@ -1,25 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE \n postgres_trigger\n SET \n last_server_ping = now(),\n error = $1\n WHERE\n workspace_id = $2\n AND path = $3\n AND server_id = $4 \n AND enabled IS TRUE\n RETURNING 1\n ",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "?column?",
"type_info": "Int4"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Text",
"Text"
]
},
"nullable": [
null
]
},
"hash": "833a4ecec12dfe67f28016a135ffe682b023d1868a182b7cac16ce799433c257"
}

View File

@@ -1,38 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT\n success AS \"success!\",\n result AS \"result: Json<Box<RawValue>>\",\n started_at AS \"started_at!\"\n FROM v2_as_completed_job\n WHERE workspace_id = $1 AND schedule_path = $2 AND script_path = $3 AND id != $4\n ORDER BY created_at DESC\n LIMIT $5",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "success!",
"type_info": "Bool"
},
{
"ordinal": 1,
"name": "result: Json<Box<RawValue>>",
"type_info": "Jsonb"
},
{
"ordinal": 2,
"name": "started_at!",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Text",
"Uuid",
"Int8"
]
},
"nullable": [
true,
true,
true
]
},
"hash": "86cc1e3c18e936a700d8842a51a6f8377ec190669e2e22f8d511871d6fbe07b8"
}

View File

@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE v2_job SET\n args = (SELECT result FROM v2_job_completed WHERE id = $1),\n preprocessed = TRUE\n WHERE id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Uuid",
"Uuid"
]
},
"nullable": []
},
"hash": "8a1c9119f6f4763f64597684dc7b312404e637212de1897e97999755a2e492fd"
}

View File

@@ -1,12 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "create index concurrently if not exists ix_job_workspace_id_created_at_new_6 ON v2_job (workspace_id, created_at DESC) where kind in ('script', 'flow') AND parent_job IS NULL",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "8be277b89102a26dda506202a3ef7eb05342cfb3aa9b4f5d80c70fbc50d437ba"
}

View File

@@ -0,0 +1,26 @@
{
"db_name": "PostgreSQL",
"query": "SELECT status = 'success' AS \"success!\"\n FROM v2_job j JOIN v2_job_completed USING (id)\n WHERE j.workspace_id = $1 AND trigger_kind = 'schedule' AND trigger = $2\n AND parent_job IS NULL\n AND runnable_path = $3\n AND j.id != $4\n ORDER BY created_at DESC\n LIMIT $5",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "success!",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Text",
"Uuid",
"Int8"
]
},
"nullable": [
null
]
},
"hash": "910b9b8afb3df5e437e43ff4adc97d0a03f6c26f0b14fc92900f7600e70a7a8b"
}

View File

@@ -1,130 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT\n -- slack_team_id, \n -- slack_name, \n -- slack_command_script, \n -- CASE WHEN slack_email = 'missing@email.xyz' THEN NULL ELSE slack_email END AS slack_email,\n auto_invite_domain IS NOT NULL AS \"auto_invite_enabled!\",\n CASE WHEN auto_invite_operator IS TRUE THEN 'operator' ELSE 'developer' END AS \"auto_invite_as!\", \n CASE WHEN auto_add IS TRUE THEN 'add' ELSE 'invite' END AS \"auto_invite_mode!\", \n webhook, \n deploy_to, \n error_handler, \n ai_resource, \n ai_models,\n code_completion_model,\n error_handler_extra_args, \n error_handler_muted_on_cancel, \n large_file_storage, \n git_sync,\n default_app,\n default_scripts,\n workspace.name,\n mute_critical_alerts,\n color,\n operator_settings\n FROM workspace_settings\n LEFT JOIN workspace ON workspace.id = workspace_settings.workspace_id\n WHERE workspace_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "auto_invite_enabled!",
"type_info": "Bool"
},
{
"ordinal": 1,
"name": "auto_invite_as!",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "auto_invite_mode!",
"type_info": "Text"
},
{
"ordinal": 3,
"name": "webhook",
"type_info": "Text"
},
{
"ordinal": 4,
"name": "deploy_to",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "error_handler",
"type_info": "Varchar"
},
{
"ordinal": 6,
"name": "ai_resource",
"type_info": "Jsonb"
},
{
"ordinal": 7,
"name": "ai_models",
"type_info": "VarcharArray"
},
{
"ordinal": 8,
"name": "code_completion_model",
"type_info": "Varchar"
},
{
"ordinal": 9,
"name": "error_handler_extra_args",
"type_info": "Json"
},
{
"ordinal": 10,
"name": "error_handler_muted_on_cancel",
"type_info": "Bool"
},
{
"ordinal": 11,
"name": "large_file_storage",
"type_info": "Jsonb"
},
{
"ordinal": 12,
"name": "git_sync",
"type_info": "Jsonb"
},
{
"ordinal": 13,
"name": "default_app",
"type_info": "Varchar"
},
{
"ordinal": 14,
"name": "default_scripts",
"type_info": "Jsonb"
},
{
"ordinal": 15,
"name": "name",
"type_info": "Varchar"
},
{
"ordinal": 16,
"name": "mute_critical_alerts",
"type_info": "Bool"
},
{
"ordinal": 17,
"name": "color",
"type_info": "Varchar"
},
{
"ordinal": 18,
"name": "operator_settings",
"type_info": "Jsonb"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
null,
null,
null,
true,
true,
true,
true,
false,
true,
true,
false,
true,
true,
true,
true,
false,
true,
true,
true
]
},
"hash": "91878f06c6e27d864bd50d8cd4adde4395ab6ef1181237a886fa398dcfa0b589"
}

View File

@@ -1,15 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE \n postgres_trigger \n SET\n last_server_ping = NULL \n WHERE \n workspace_id = $1 \n AND path = $2 \n AND server_id IS NULL",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": []
},
"hash": "95e420b60fba20b36b2c6675998587d8cad3b67d4dfa9de52777d4ea9490b6b7"
}

View File

@@ -1,24 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT EXISTS (SELECT 1 FROM v2_as_queue WHERE workspace_id = $1 AND schedule_path = $2 AND scheduled_for = $3)",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "exists",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Timestamptz"
]
},
"nullable": [
null
]
},
"hash": "9e7e6fe1dfba032e586f64531e12529d57faf5e77f6792d5bda608ff9658d7c9"
}

View File

@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE postgres_trigger SET enabled = FALSE, error = $1, server_id = NULL, last_server_ping = NULL WHERE workspace_id = $2 AND path = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text",
"Text"
]
},
"nullable": []
},
"hash": "a6c168c60bc8c42f70b18565e824efe29311aabfba6e09efa10bab6a551d658b"
}

View File

@@ -1,106 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT * FROM kafka_trigger\n WHERE workspace_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "path",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "kafka_resource_path",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "topics",
"type_info": "VarcharArray"
},
{
"ordinal": 3,
"name": "group_id",
"type_info": "Varchar"
},
{
"ordinal": 4,
"name": "script_path",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "is_flow",
"type_info": "Bool"
},
{
"ordinal": 6,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 7,
"name": "edited_by",
"type_info": "Varchar"
},
{
"ordinal": 8,
"name": "email",
"type_info": "Varchar"
},
{
"ordinal": 9,
"name": "edited_at",
"type_info": "Timestamptz"
},
{
"ordinal": 10,
"name": "extra_perms",
"type_info": "Jsonb"
},
{
"ordinal": 11,
"name": "server_id",
"type_info": "Varchar"
},
{
"ordinal": 12,
"name": "last_server_ping",
"type_info": "Timestamptz"
},
{
"ordinal": 13,
"name": "error",
"type_info": "Text"
},
{
"ordinal": 14,
"name": "enabled",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
false,
true,
true,
true,
false
]
},
"hash": "a79b1d0884c02f92fd40b23c6181717ffa5e01250020cfb24e4bad276397dee2"
}

View File

@@ -1,12 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "create index concurrently if not exists ix_job_workspace_id_created_at_new_7 ON v2_job (workspace_id, created_at DESC) where kind in ('script', 'flow') AND parent_job IS NULL",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "ae8dfecd46425d5f86003eea9a578e9831fc0e700cc76ab9627afe9040a4efe0"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "VACUUM v2_job_queue, v2_job_runtime, v2_job_status",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "b9b38d63af3670d1f11d5cbb82a8008a9479bf4b3d7231371ebf26382ecde365"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "ALTER TABLE v2_job ENABLE ROW LEVEL SECURITY",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "c458012c39f1327fb2bfd6b087ee6dbe1380eca532f50bab0cb89a91d42131cf"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "create index concurrently if not exists ix_job_root_job_index_by_path_2 ON v2_job (workspace_id, runnable_path, created_at desc) WHERE parent_job IS NULL",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "c481e5d63ebf1aa537cc4ce4e84f9a71af5996bc76f328b3ba1cf68a71880462"
}

View File

@@ -1,6 +1,6 @@
{
"db_name": "PostgreSQL",
"query": "DELETE FROM v2_job_queue WHERE workspace_id = $1 AND id = $2 RETURNING 1",
"query": "DELETE FROM v2_job_queue WHERE id = $1 RETURNING 1",
"describe": {
"columns": [
{
@@ -11,7 +11,6 @@
],
"parameters": {
"Left": [
"Text",
"Uuid"
]
},
@@ -19,5 +18,5 @@
null
]
},
"hash": "d25c58d2722ad3dcd91101ce6f66e1d802dd5d82e1cd5f5ed3a15cbc75eb6745"
"hash": "c92cc71e6d10c41368f7aa75b0799c2e1e9ca0ed33077ade8d7560e7cc21fa06"
}

View File

@@ -1,46 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT g_.workspace_id, name, summary, extra_perms, array_agg(u2g.usr) filter (where u2g.usr is not null) as members \n FROM usr u\n JOIN usr_to_group u2g ON u2g.usr = u.username AND u2g.workspace_id = u.workspace_id\n RIGHT JOIN group_ g_ ON g_.workspace_id = u.workspace_id AND g_.name = u2g.group_\n WHERE g_.workspace_id = $1 AND g_.name != 'all'\n GROUP BY g_.workspace_id, name, summary, extra_perms",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "name",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "summary",
"type_info": "Text"
},
{
"ordinal": 3,
"name": "extra_perms",
"type_info": "Jsonb"
},
{
"ordinal": 4,
"name": "members",
"type_info": "VarcharArray"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
true,
false,
null
]
},
"hash": "ca5f42cb0e368d0817461600152aabefe718829fb6eae2f681c4c8328acc94b2"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "create index concurrently if not exists ix_v2_job_workspace_id_created_at ON v2_job (workspace_id, created_at DESC) where kind in ('script', 'flow', 'singlescriptflow') AND parent_job IS NULL",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "d585aa6301c41308b02a1f0fbf068221e732e48dfa6e34d5b025adbbdcbb03e0"
}

View File

@@ -1,24 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT id AS \"id!\" FROM v2_as_queue WHERE schedule_path = $1 AND workspace_id = $2 AND id != $3 AND running = true",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id!",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Uuid"
]
},
"nullable": [
true
]
},
"hash": "d6c8f4e49cf7b6db5c979c88e02bd41c7b823186ac056a0a676da85dc5d9a027"
}

View File

@@ -1,16 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE v2_job_status\n SET flow_status = JSONB_SET(flow_status, ARRAY['modules', $1::TEXT], $2)\n WHERE id = $3",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Jsonb",
"Uuid"
]
},
"nullable": []
},
"hash": "db91141ae55b96a3237e05e3f127386339cb3c7a6f88bb2102498ec5d34f9537"
}

View File

@@ -15,7 +15,7 @@
]
},
"nullable": [
null
true
]
},
"hash": "ddf2eccb78a310ed00c7d8b9c3f05d394a7cbcf0038c72a78add5c7b02ef5927"

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "\n UPDATE global_settings\n SET value = (\n SELECT jsonb_agg(elem)\n FROM jsonb_array_elements(value) AS elem\n WHERE NOT (elem ? 'teams_channel')\n )\n WHERE name = 'critical_error_channels'\n ",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "df3b60c1d0fb44c97bf2611a7cda6bdb16a1be66e993a5cfadf6de2e3c8a5021"
}

View File

@@ -0,0 +1,14 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE global_settings SET value = $1 WHERE name = 'teams'",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Jsonb"
]
},
"nullable": []
},
"hash": "e565f3b2e51059f563d18a8a9442bcae9640cee7b936820cb46c011222a77ff0"
}

View File

@@ -0,0 +1,38 @@
{
"db_name": "PostgreSQL",
"query": "SELECT status = 'success' AS \"success!\",\n result AS \"result: Json<Box<RawValue>>\",\n started_at AS \"started_at!\"FROM v2_job j JOIN v2_job_completed USING (id)\n WHERE j.workspace_id = $1 AND trigger_kind = 'schedule' AND trigger = $2\n AND parent_job IS NULL\n AND runnable_path = $3\n AND j.id != $4\n ORDER BY created_at DESC\n LIMIT $5",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "success!",
"type_info": "Bool"
},
{
"ordinal": 1,
"name": "result: Json<Box<RawValue>>",
"type_info": "Jsonb"
},
{
"ordinal": 2,
"name": "started_at!",
"type_info": "Timestamptz"
}
],
"parameters": {
"Left": [
"Text",
"Text",
"Text",
"Uuid",
"Int8"
]
},
"nullable": [
null,
true,
true
]
},
"hash": "e6a8ddfd74ebab55ede5989fd7d09b246b6f84e49c659bc8e2c7b66cfec6d976"
}

View File

@@ -0,0 +1,15 @@
{
"db_name": "PostgreSQL",
"query": "UPDATE workspace_settings SET teams_command_script = $1 WHERE workspace_id = $2",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": []
},
"hash": "ebbe03cad470d0c6ae98964f630315ff25dad08e4cb714718505b77a75d44b95"
}

View File

@@ -1,64 +0,0 @@
{
"db_name": "PostgreSQL",
"query": "SELECT * FROM usr\n WHERE workspace_id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "username",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "email",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "is_admin",
"type_info": "Bool"
},
{
"ordinal": 4,
"name": "created_at",
"type_info": "Timestamptz"
},
{
"ordinal": 5,
"name": "operator",
"type_info": "Bool"
},
{
"ordinal": 6,
"name": "disabled",
"type_info": "Bool"
},
{
"ordinal": 7,
"name": "role",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false,
false,
false,
false,
false,
false,
false,
true
]
},
"hash": "f96dd1dd944506c07ad58d178e9b6a09259fedca329d790c34e58703bf26f34c"
}

View File

@@ -0,0 +1,12 @@
{
"db_name": "PostgreSQL",
"query": "DROP INDEX CONCURRENTLY IF EXISTS ix_job_workspace_id_created_at_new_6",
"describe": {
"columns": [],
"parameters": {
"Left": []
},
"nullable": []
},
"hash": "faa0e401e6beebde6c3fef06151d3e73a5806f61cae4a53b5bdc888ec7164395"
}

View File

@@ -1,31 +1,31 @@
{
"db_name": "PostgreSQL",
"query": "SELECT workspace.id, workspace.name, workspace.owner, workspace.deleted, workspace.premium, workspace_settings.color\n FROM workspace\n LEFT JOIN workspace_settings ON workspace.id = workspace_settings.workspace_id\n LIMIT $1 OFFSET $2",
"query": "SELECT\n workspace.id AS \"id!\",\n workspace.name AS \"name!\",\n workspace.owner AS \"owner!\",\n workspace.deleted AS \"deleted!\",\n workspace.premium AS \"premium!\",\n workspace_settings.color AS \"color\"\n FROM workspace\n LEFT JOIN workspace_settings ON workspace.id = workspace_settings.workspace_id\n LIMIT $1 OFFSET $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"name": "id!",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "name",
"name": "name!",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "owner",
"name": "owner!",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "deleted",
"name": "deleted!",
"type_info": "Bool"
},
{
"ordinal": 4,
"name": "premium",
"name": "premium!",
"type_info": "Bool"
},
{
@@ -49,5 +49,5 @@
true
]
},
"hash": "eed16e356f3f36183c3db13fcc1950295e0d0fbdabb38434534fb3430eeddc25"
"hash": "fec6d5674dc6b5a6a0ece419c40508835affcb7679a48f2a443777e829bd1e74"
}

162
backend/Cargo.lock generated
View File

@@ -492,7 +492,7 @@ dependencies = [
"portable-atomic",
"rand 0.8.5",
"regex",
"ring 0.17.8",
"ring 0.17.9",
"rustls-native-certs 0.7.3",
"rustls-pemfile 2.2.0",
"rustls-webpki 0.102.8",
@@ -671,7 +671,7 @@ dependencies = [
"fastrand 2.3.0",
"hex",
"http 0.2.12",
"ring 0.17.8",
"ring 0.17.9",
"time",
"tokio",
"tracing",
@@ -718,9 +718,9 @@ dependencies = [
[[package]]
name = "aws-sdk-sso"
version = "1.58.0"
version = "1.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16ff718c9ee45cc1ebd4774a0e086bb80a6ab752b4902edf1c9f56b86ee1f770"
checksum = "00a35fc7e74f5be45839eb753568535c074a592185dd0a2d406685018d581c43"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -740,9 +740,9 @@ dependencies = [
[[package]]
name = "aws-sdk-ssooidc"
version = "1.59.0"
version = "1.60.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5183e088715cc135d8d396fdd3bc02f018f0da4c511f53cb8d795b6a31c55809"
checksum = "f8fa655b4f313124ce272cbc38c5fef13793c832279cec750103e5e6b71a54b8"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -762,9 +762,9 @@ dependencies = [
[[package]]
name = "aws-sdk-sts"
version = "1.59.0"
version = "1.60.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9f944ef032717596639cea4a2118a3a457268ef51bbb5fde9637e54c465da00"
checksum = "dc1cfe5e16b90421ea031f4c6348b534ef442e76f6bf4a1b2b592c12cc2c6af9"
dependencies = [
"aws-credential-types",
"aws-runtime",
@@ -785,9 +785,9 @@ dependencies = [
[[package]]
name = "aws-sigv4"
version = "1.2.8"
version = "1.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bc5bbd1e4a2648fd8c5982af03935972c24a2f9846b396de661d351ee3ce837"
checksum = "9bfe75fad52793ce6dec0dc3d4b1f388f038b5eb866c8d4d7f3a8e21b5ea5051"
dependencies = [
"aws-credential-types",
"aws-smithy-http",
@@ -1552,9 +1552,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.2.13"
version = "1.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda"
checksum = "0c3d1b2e905a3a7b00a6141adb0e4c0bb941d11caf55349d863942a1cc44e3c9"
dependencies = [
"jobserver",
"libc",
@@ -1668,9 +1668,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.29"
version = "4.5.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8acebd8ad879283633b343856142139f2da2317c96b05b4dd6181c61e2480184"
checksum = "92b7b18d71fad5313a1e320fa9897994228ce274b60faa4d694fe0ea89cd9e6d"
dependencies = [
"clap_builder",
"clap_derive",
@@ -1678,9 +1678,9 @@ dependencies = [
[[package]]
name = "clap_builder"
version = "4.5.29"
version = "4.5.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6ba32cbda51c7e1dfd49acc1457ba1a7dec5b64fe360e828acb13ca8dc9c2f9"
checksum = "a35db2071778a7344791a4fb4f95308b5673d219dee3ae348b86642574ecc90c"
dependencies = [
"anstream",
"anstyle",
@@ -2050,9 +2050,9 @@ dependencies = [
[[package]]
name = "csv-core"
version = "0.1.11"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70"
checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d"
dependencies = [
"memchr",
]
@@ -3209,9 +3209,9 @@ dependencies = [
[[package]]
name = "equivalent"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
@@ -5673,7 +5673,7 @@ dependencies = [
"quick-xml 0.36.2",
"rand 0.8.5",
"reqwest 0.12.9",
"ring 0.17.8",
"ring 0.17.9",
"serde",
"serde_json",
"snafu",
@@ -5776,9 +5776,9 @@ dependencies = [
[[package]]
name = "openssl"
version = "0.10.70"
version = "0.10.71"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6"
checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd"
dependencies = [
"bitflags 2.8.0",
"cfg-if",
@@ -5817,9 +5817,9 @@ dependencies = [
[[package]]
name = "openssl-sys"
version = "0.9.105"
version = "0.9.106"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc"
checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd"
dependencies = [
"cc",
"libc",
@@ -6608,9 +6608,9 @@ dependencies = [
[[package]]
name = "psm"
version = "0.1.24"
version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810"
checksum = "f58e5423e24c18cc840e1c98370b3993c6649cd1678b4d24318bcf0a083cbe88"
dependencies = [
"cc",
]
@@ -6724,7 +6724,7 @@ dependencies = [
"bytes",
"getrandom 0.2.15",
"rand 0.8.5",
"ring 0.17.8",
"ring 0.17.9",
"rustc-hash 2.1.1",
"rustls 0.23.23",
"rustls-pki-types",
@@ -6737,9 +6737,9 @@ dependencies = [
[[package]]
name = "quinn-udp"
version = "0.5.9"
version = "0.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904"
checksum = "e46f3055866785f6b92bc6164b76be02ca8f2eb4b002c0354b28cf4c119e5944"
dependencies = [
"cfg_aliases",
"libc",
@@ -6795,8 +6795,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
dependencies = [
"rand_chacha 0.9.0",
"rand_core 0.9.0",
"zerocopy 0.8.17",
"rand_core 0.9.1",
"zerocopy 0.8.18",
]
[[package]]
@@ -6826,7 +6826,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core 0.9.0",
"rand_core 0.9.1",
]
[[package]]
@@ -6849,12 +6849,12 @@ dependencies = [
[[package]]
name = "rand_core"
version = "0.9.0"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff"
checksum = "a88e0da7a2c97baa202165137c158d0a2e824ac465d13d81046727b34cb247d3"
dependencies = [
"getrandom 0.3.1",
"zerocopy 0.8.17",
"zerocopy 0.8.18",
]
[[package]]
@@ -7195,15 +7195,14 @@ dependencies = [
[[package]]
name = "ring"
version = "0.17.8"
version = "0.17.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
checksum = "e75ec5e92c4d8aede845126adc388046234541629e76029599ed35a003c7ed24"
dependencies = [
"cc",
"cfg-if",
"getrandom 0.2.15",
"libc",
"spin 0.9.8",
"untrusted 0.9.0",
"windows-sys 0.52.0",
]
@@ -7388,7 +7387,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e"
dependencies = [
"log",
"ring 0.17.8",
"ring 0.17.9",
"rustls-webpki 0.101.7",
"sct",
]
@@ -7401,7 +7400,7 @@ checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395"
dependencies = [
"log",
"once_cell",
"ring 0.17.8",
"ring 0.17.9",
"rustls-pki-types",
"rustls-webpki 0.102.8",
"subtle",
@@ -7490,7 +7489,7 @@ version = "0.101.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
dependencies = [
"ring 0.17.8",
"ring 0.17.9",
"untrusted 0.9.0",
]
@@ -7500,7 +7499,7 @@ version = "0.102.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9"
dependencies = [
"ring 0.17.8",
"ring 0.17.9",
"rustls-pki-types",
"untrusted 0.9.0",
]
@@ -7576,9 +7575,9 @@ checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
[[package]]
name = "ryu-js"
version = "1.0.1"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad97d4ce1560a5e27cec89519dc8300d1aa6035b099821261c651486a19e44d5"
checksum = "dd29631678d6fb0903b69223673e122c32e9ae559d0960a38d574695ebc0ea15"
[[package]]
name = "safetensors"
@@ -7685,7 +7684,7 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
dependencies = [
"ring 0.17.8",
"ring 0.17.9",
"untrusted 0.9.0",
]
@@ -8151,9 +8150,9 @@ dependencies = [
[[package]]
name = "smallvec"
version = "1.13.2"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd"
dependencies = [
"serde",
]
@@ -9298,9 +9297,9 @@ dependencies = [
[[package]]
name = "tempfile"
version = "3.16.0"
version = "3.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91"
checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230"
dependencies = [
"cfg-if",
"fastrand 2.3.0",
@@ -9763,7 +9762,7 @@ dependencies = [
"http 1.2.0",
"httparse",
"rand 0.8.5",
"ring 0.17.8",
"ring 0.17.9",
"rustls-native-certs 0.8.1",
"rustls-pki-types",
"tokio",
@@ -10859,7 +10858,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windmill"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"anyhow",
"axum",
@@ -10902,7 +10901,7 @@ dependencies = [
[[package]]
name = "windmill-api"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"anyhow",
"argon2",
@@ -10989,13 +10988,14 @@ dependencies = [
"windmill-git-sync",
"windmill-indexer",
"windmill-parser",
"windmill-parser-py",
"windmill-parser-ts",
"windmill-queue",
]
[[package]]
name = "windmill-api-client"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"base64 0.22.1",
"chrono",
@@ -11013,7 +11013,7 @@ dependencies = [
[[package]]
name = "windmill-audit"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"chrono",
"serde",
@@ -11026,7 +11026,7 @@ dependencies = [
[[package]]
name = "windmill-autoscaling"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"anyhow",
"serde",
@@ -11040,7 +11040,7 @@ dependencies = [
[[package]]
name = "windmill-common"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"anyhow",
"async-stream",
@@ -11099,7 +11099,7 @@ dependencies = [
[[package]]
name = "windmill-git-sync"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"regex",
"serde",
@@ -11113,7 +11113,7 @@ dependencies = [
[[package]]
name = "windmill-indexer"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"anyhow",
"bytes",
@@ -11136,7 +11136,7 @@ dependencies = [
[[package]]
name = "windmill-macros"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"itertools 0.14.0",
"lazy_static",
@@ -11148,7 +11148,7 @@ dependencies = [
[[package]]
name = "windmill-parser"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"convert_case 0.6.0",
"serde",
@@ -11157,7 +11157,7 @@ dependencies = [
[[package]]
name = "windmill-parser-bash"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"anyhow",
"lazy_static",
@@ -11169,7 +11169,7 @@ dependencies = [
[[package]]
name = "windmill-parser-csharp"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"anyhow",
"serde_json",
@@ -11181,7 +11181,7 @@ dependencies = [
[[package]]
name = "windmill-parser-go"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"anyhow",
"gosyn",
@@ -11193,7 +11193,7 @@ dependencies = [
[[package]]
name = "windmill-parser-graphql"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"anyhow",
"lazy_static",
@@ -11205,7 +11205,7 @@ dependencies = [
[[package]]
name = "windmill-parser-php"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"anyhow",
"itertools 0.14.0",
@@ -11216,7 +11216,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"anyhow",
"itertools 0.14.0",
@@ -11227,7 +11227,7 @@ dependencies = [
[[package]]
name = "windmill-parser-py-imports"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"anyhow",
"async-recursion",
@@ -11247,7 +11247,7 @@ dependencies = [
[[package]]
name = "windmill-parser-rust"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"anyhow",
"convert_case 0.6.0",
@@ -11264,7 +11264,7 @@ dependencies = [
[[package]]
name = "windmill-parser-sql"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"anyhow",
"lazy_static",
@@ -11276,7 +11276,7 @@ dependencies = [
[[package]]
name = "windmill-parser-ts"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"anyhow",
"lazy_static",
@@ -11294,7 +11294,7 @@ dependencies = [
[[package]]
name = "windmill-parser-wasm"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"anyhow",
"getrandom 0.2.15",
@@ -11316,7 +11316,7 @@ dependencies = [
[[package]]
name = "windmill-parser-yaml"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"anyhow",
"serde_json",
@@ -11326,7 +11326,7 @@ dependencies = [
[[package]]
name = "windmill-queue"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"anyhow",
"async-recursion",
@@ -11359,7 +11359,7 @@ dependencies = [
[[package]]
name = "windmill-sql-datatype-parser-wasm"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"wasm-bindgen",
"wasm-bindgen-test",
@@ -11369,7 +11369,7 @@ dependencies = [
[[package]]
name = "windmill-worker"
version = "1.460.1"
version = "1.463.4"
dependencies = [
"anyhow",
"async-recursion",
@@ -11783,11 +11783,11 @@ dependencies = [
[[package]]
name = "zerocopy"
version = "0.8.17"
version = "0.8.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa91407dacce3a68c56de03abe2760159582b846c6a4acd2f456618087f12713"
checksum = "79386d31a42a4996e3336b0919ddb90f81112af416270cff95b5f5af22b839c2"
dependencies = [
"zerocopy-derive 0.8.17",
"zerocopy-derive 0.8.18",
]
[[package]]
@@ -11803,9 +11803,9 @@ dependencies = [
[[package]]
name = "zerocopy-derive"
version = "0.8.17"
version = "0.8.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06718a168365cad3d5ff0bb133aad346959a2074bd4a85c121255a11304a8626"
checksum = "76331675d372f91bf8d17e13afbd5fe639200b73d01f0fc748bb059f9cca2db7"
dependencies = [
"proc-macro2",
"quote",

View File

@@ -1,6 +1,6 @@
[package]
name = "windmill"
version = "1.460.1"
version = "1.463.4"
authors.workspace = true
edition.workspace = true
@@ -30,7 +30,7 @@ members = [
]
[workspace.package]
version = "1.460.1"
version = "1.463.4"
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
edition = "2021"
@@ -187,7 +187,7 @@ hex = "^0"
sql-builder = "^3"
argon2 = "^0"
quick_cache = "^0"
rand = "^0"
rand = "=0.9.0"
rand_core = { version = "^0", features = ["std"] }
magic-crypt = "^3"
git-version = "^0"

View File

@@ -1 +1 @@
8dab3198496461e40610145e4c818fce2345e20a
e507af5589efb1a8a72ae4e231130f749bde738d

View File

@@ -0,0 +1,3 @@
ALTER TABLE workspace_settings DROP COLUMN teams_command_script;
ALTER TABLE workspace_settings DROP COLUMN teams_team_id;
ALTER TABLE workspace_settings DROP COLUMN teams_team_name;

View File

@@ -0,0 +1,3 @@
ALTER TABLE workspace_settings ADD COLUMN teams_command_script TEXT DEFAULT NULL;
ALTER TABLE workspace_settings ADD COLUMN teams_team_id TEXT DEFAULT NULL;
ALTER TABLE workspace_settings ADD COLUMN teams_team_name TEXT DEFAULT NULL;

View File

@@ -0,0 +1 @@
-- Add down migration script here

View File

@@ -0,0 +1,42 @@
-- Add up migration script here
CREATE OR REPLACE VIEW v2_as_completed_job AS
SELECT
j.id,
j.workspace_id,
j.parent_job,
j.created_by,
j.created_at,
c.duration_ms,
c.status = 'success' OR c.status = 'skipped' AS success,
j.runnable_id AS script_hash,
j.runnable_path AS script_path,
j.args,
c.result,
FALSE AS deleted,
j.raw_code,
c.status = 'canceled' AS canceled,
c.canceled_by,
c.canceled_reason,
j.kind AS job_kind,
CASE WHEN j.trigger_kind = 'schedule'::job_trigger_kind THEN j.trigger END
AS schedule_path,
j.permissioned_as,
COALESCE(c.flow_status, c.workflow_as_code_status) AS flow_status,
j.raw_flow,
j.flow_step_id IS NOT NULL AS is_flow_step,
j.script_lang AS language,
c.started_at,
c.status = 'skipped' AS is_skipped,
j.raw_lock,
j.permissioned_as_email AS email,
j.visible_to_owner,
c.memory_peak AS mem_peak,
j.tag,
j.priority,
NULL::TEXT AS logs,
c.result_columns,
j.script_entrypoint_override,
j.preprocessed
FROM v2_job_completed c
JOIN v2_job j USING (id)
;

View File

@@ -0,0 +1 @@
-- Add down migration script here

View File

@@ -0,0 +1,8 @@
-- Add up migration script here
DROP POLICY IF EXISTS see_own ON v2_job;
CREATE POLICY see_own ON v2_job
AS PERMISSIVE
FOR ALL
TO windmill_user
USING ((SPLIT_PART((permissioned_as)::TEXT, '/'::TEXT, 1) = 'u'::TEXT) AND
(SPLIT_PART((permissioned_as)::TEXT, '/'::TEXT, 2) = CURRENT_SETTING('session.user'::TEXT)));

View File

@@ -0,0 +1 @@
-- Add down migration script here

View File

@@ -0,0 +1,3 @@
-- Add up migration script here
DROP POLICY IF EXISTS admin_policy ON v2_job;
CREATE POLICY admin_policy ON v2_job FOR ALL TO windmill_admin USING (true);

View File

@@ -60,6 +60,7 @@ fn filter_non_main(code: &str, main_name: &str) -> String {
pub fn parse_python_signature(
code: &str,
override_main: Option<String>,
skip_params: bool,
) -> anyhow::Result<MainArgSignature> {
let main_name = override_main.unwrap_or("main".to_string());
@@ -78,11 +79,13 @@ pub fn parse_python_signature(
let ast = Suite::parse(&filtered_code, "main.py")
.map_err(|e| anyhow::anyhow!("Error parsing code: {}", e.to_string()))?;
let param = ast.into_iter().find_map(|x| match x {
let params = ast.into_iter().find_map(|x| match x {
Stmt::FunctionDef(StmtFunctionDef { name, args, .. }) if &name == &main_name => Some(*args),
_ => None,
});
if let Some(params) = param {
if !skip_params && params.is_some() {
let params = params.unwrap();
//println!("{:?}", params);
let def_arg_start = params.args.len() - params.defaults().count();
Ok(MainArgSignature {
@@ -149,7 +152,7 @@ pub fn parse_python_signature(
star_args: false,
star_kwargs: false,
args: vec![],
no_main_func: Some(true),
no_main_func: Some(params.is_none()),
has_preprocessor: Some(has_preprocessor),
})
}
@@ -287,7 +290,7 @@ def main(test1: str, name: datetime.datetime = datetime.now(), byte: bytes = byt
";
//println!("{}", serde_json::to_string()?);
assert_eq!(
parse_python_signature(code, None)?,
parse_python_signature(code, None, false)?,
MainArgSignature {
star_args: false,
star_kwargs: false,
@@ -376,7 +379,7 @@ def main(test1: str,
";
//println!("{}", serde_json::to_string()?);
assert_eq!(
parse_python_signature(code, None)?,
parse_python_signature(code, None, false)?,
MainArgSignature {
star_args: false,
star_kwargs: false,
@@ -436,7 +439,7 @@ def main(test1: str,
";
//println!("{}", serde_json::to_string()?);
assert_eq!(
parse_python_signature(code, None)?,
parse_python_signature(code, None, false)?,
MainArgSignature {
star_args: false,
star_kwargs: false,
@@ -493,7 +496,7 @@ def main(test1: Literal["foo", "bar"], test2: List[Literal["foo", "bar"]]): retu
"#;
//println!("{}", serde_json::to_string()?);
assert_eq!(
parse_python_signature(code, None)?,
parse_python_signature(code, None, false)?,
MainArgSignature {
star_args: false,
star_kwargs: false,
@@ -537,7 +540,7 @@ def main(test1: DynSelect_foo): return
"#;
//println!("{}", serde_json::to_string()?);
assert_eq!(
parse_python_signature(code, None)?,
parse_python_signature(code, None, false)?,
MainArgSignature {
star_args: false,
star_kwargs: false,
@@ -568,7 +571,7 @@ def hello(): return
"#;
//println!("{}", serde_json::to_string()?);
assert_eq!(
parse_python_signature(code, None)?,
parse_python_signature(code, None, false)?,
MainArgSignature {
star_args: false,
star_kwargs: false,
@@ -596,7 +599,7 @@ def main(): return
"#;
//println!("{}", serde_json::to_string()?);
assert_eq!(
parse_python_signature(code, None)?,
parse_python_signature(code, None, false)?,
MainArgSignature {
star_args: false,
star_kwargs: false,
@@ -617,10 +620,10 @@ def main(a: list, e: List[int], b: list = [1,2,3,4], c = [1,2,3,4], d = ["a", "b
"#;
println!(
"{}",
serde_json::to_string(&parse_python_signature(code, None)?)?
serde_json::to_string(&parse_python_signature(code, None, false)?)?
);
assert_eq!(
parse_python_signature(code, None)?,
parse_python_signature(code, None, false)?,
MainArgSignature {
star_args: false,
star_kwargs: false,

View File

@@ -134,6 +134,7 @@ pub fn parse_expr_for_ids(code: &str) -> anyhow::Result<Vec<(String, String)>> {
pub fn parse_deno_signature(
code: &str,
skip_dflt: bool,
skip_params: bool,
main_override: Option<String>,
) -> anyhow::Result<MainArgSignature> {
let cm: Lrc<SourceMap> = Default::default();
@@ -179,27 +180,26 @@ pub fn parse_deno_signature(
});
let mut c: u16 = 0;
if let Some(params) = params {
let r = MainArgSignature {
star_args: false,
star_kwargs: false,
args: params
.into_iter()
.map(|x| parse_param(x, &cm, skip_dflt, &mut c))
.collect::<anyhow::Result<Vec<Arg>>>()?,
no_main_func: Some(false),
has_preprocessor: Some(has_preprocessor),
};
Ok(r)
} else {
Ok(MainArgSignature {
star_args: false,
star_kwargs: false,
args: vec![],
no_main_func: Some(true),
has_preprocessor: Some(has_preprocessor),
})
}
let no_main_func = params.is_none();
let r = MainArgSignature {
star_args: false,
star_kwargs: false,
args: if skip_params {
vec![]
} else {
params
.map(|x| {
x.into_iter()
.map(|x| parse_param(x, &cm, skip_dflt, &mut c))
.collect::<anyhow::Result<Vec<Arg>>>()
})
.transpose()?
.unwrap_or_else(|| vec![])
},
no_main_func: Some(no_main_func),
has_preprocessor: Some(has_preprocessor),
};
Ok(r)
}
fn parse_param(

View File

@@ -17,10 +17,11 @@ fn wrap_sig(r: anyhow::Result<MainArgSignature>) -> String {
#[cfg(feature = "ts-parser")]
#[wasm_bindgen]
pub fn parse_deno(code: &str, main_override: Option<String>) -> String {
pub fn parse_deno(code: &str, main_override: Option<String>, skip_params: Option<bool>) -> String {
wrap_sig(windmill_parser_ts::parse_deno_signature(
code,
false,
false,
main_override,
))
}
@@ -73,6 +74,7 @@ pub fn parse_python(code: &str, main_override: Option<String>) -> String {
wrap_sig(windmill_parser_py::parse_python_signature(
code,
main_override,
false,
))
}

View File

@@ -18,7 +18,7 @@ export function main(test1?: string, test2: string = \"burkina\",
}
";
assert_eq!(
parse_deno_signature(code, false, None)?,
parse_deno_signature(code, false, false, None)?,
MainArgSignature {
star_args: false,
star_kwargs: false,
@@ -159,7 +159,7 @@ export function main(test2 = \"burkina\",
}
";
assert_eq!(
parse_deno_signature(code, false, None)?,
parse_deno_signature(code, false, false, None)?,
MainArgSignature {
star_args: false,
star_kwargs: false,
@@ -236,7 +236,7 @@ export function main(foo: FooBar, {a, b}: FooBar, {c, d}: FooBar = {a: \"foo\",
}
";
assert_eq!(
parse_deno_signature(code, false, None)?,
parse_deno_signature(code, false, false, None)?,
MainArgSignature {
star_args: false,
star_kwargs: false,
@@ -282,7 +282,7 @@ export function main(foo: (\"foo\" | \"bar\")[]) {
}
";
assert_eq!(
parse_deno_signature(code, false, None)?,
parse_deno_signature(code, false, false, None)?,
MainArgSignature {
star_args: false,
star_kwargs: false,

0
backend/pg_log_tail Normal file
View File

View File

@@ -66,12 +66,11 @@ use windmill_common::METRICS_ADDR;
use windmill_common::global_settings::OBJECT_STORE_CACHE_CONFIG_SETTING;
use windmill_worker::{
get_hub_script_content_and_requirements, BUN_BUNDLE_CACHE_DIR, BUN_CACHE_DIR,
BUN_DEPSTAR_CACHE_DIR, CSHARP_CACHE_DIR, DENO_CACHE_DIR, DENO_CACHE_DIR_DEPS,
DENO_CACHE_DIR_NPM, GO_BIN_CACHE_DIR, GO_CACHE_DIR, LOCK_CACHE_DIR, PIP_CACHE_DIR,
POWERSHELL_CACHE_DIR, PY310_CACHE_DIR, PY311_CACHE_DIR, PY312_CACHE_DIR, PY313_CACHE_DIR,
RUST_CACHE_DIR, TAR_PIP_CACHE_DIR, TAR_PY310_CACHE_DIR, TAR_PY311_CACHE_DIR,
TAR_PY312_CACHE_DIR, TAR_PY313_CACHE_DIR, UV_CACHE_DIR,
get_hub_script_content_and_requirements, BUN_BUNDLE_CACHE_DIR, BUN_CACHE_DIR, CSHARP_CACHE_DIR,
DENO_CACHE_DIR, DENO_CACHE_DIR_DEPS, DENO_CACHE_DIR_NPM, GO_BIN_CACHE_DIR, GO_CACHE_DIR,
LOCK_CACHE_DIR, PIP_CACHE_DIR, POWERSHELL_CACHE_DIR, PY310_CACHE_DIR, PY311_CACHE_DIR,
PY312_CACHE_DIR, PY313_CACHE_DIR, RUST_CACHE_DIR, TAR_PIP_CACHE_DIR, TAR_PY310_CACHE_DIR,
TAR_PY311_CACHE_DIR, TAR_PY312_CACHE_DIR, TAR_PY313_CACHE_DIR, UV_CACHE_DIR,
};
use crate::monitor::{
@@ -1042,7 +1041,6 @@ pub async fn run_workers(
TAR_PY312_CACHE_DIR,
TAR_PY313_CACHE_DIR,
PIP_CACHE_DIR,
BUN_DEPSTAR_CACHE_DIR,
BUN_BUNDLE_CACHE_DIR,
GO_CACHE_DIR,
GO_BIN_CACHE_DIR,

View File

@@ -68,7 +68,7 @@ fi
if [ "$REVERT" == "YES" ]; then
for ee_file in $(find ${EE_CODE_DIR} -name "*ee.rs"); do
ce_file="${ee_file/${EE_CODE_DIR}/.}"
ce_file="${ee_file/${EE_CODE_DIR}/}"
ce_file="${root_dirpath}/backend/${ce_file}"
if [ "$REVERT_PREVIOUS" == "YES" ]; then
git checkout HEAD@{3} ${ce_file} || true
@@ -80,7 +80,7 @@ if [ "$REVERT" == "YES" ]; then
else
# This replaces all files in current repo with alternative EE files in windmill-ee-private
for ee_file in $(find "${EE_CODE_DIR}" -name "*ee.rs"); do
ce_file="${ee_file/${EE_CODE_DIR}/.}"
ce_file="${ee_file/${EE_CODE_DIR}/}"
ce_file="${root_dirpath}/backend/${ce_file}"
if [[ -f "${ce_file}" ]]; then
rm "${ce_file}"

View File

@@ -53,183 +53,74 @@ EXECUTE FUNCTION "notify_queue" ();
WHEN (NEW.flow_status IS DISTINCT FROM OLD.flow_status)
EXECUTE FUNCTION "notify_queue" ();
-- TODO(uael): remove before phase 4
CREATE OR REPLACE FUNCTION zzz_v2_job_queue_integrity_check() RETURNS TRIGGER AS $$
DECLARE job v2_job;
DECLARE job_runtime v2_job_runtime;
DECLARE job_status v2_job_status;
BEGIN
IF (OLD.canceled_by IS NOT NULL) IS DISTINCT FROM OLD.__canceled THEN
RAISE EXCEPTION 'canceled mismatch';
END IF;
-- v2_job:
SELECT * INTO job FROM v2_job WHERE id = OLD.id;
IF job.tag IS DISTINCT FROM OLD.tag THEN
RAISE EXCEPTION 'tag mismatch';
END IF;
IF job.workspace_id IS DISTINCT FROM OLD.workspace_id THEN
RAISE EXCEPTION 'workspace_id mismatch';
END IF;
IF job.created_at IS DISTINCT FROM OLD.created_at THEN
RAISE EXCEPTION 'created_at mismatch';
END IF;
IF job.created_by IS DISTINCT FROM OLD.__created_by THEN
RAISE EXCEPTION 'created_by mismatch';
END IF;
IF job.permissioned_as IS DISTINCT FROM OLD.__permissioned_as THEN
RAISE EXCEPTION 'permissioned_as mismatch';
END IF;
IF job.permissioned_as_email IS DISTINCT FROM OLD.__email THEN
RAISE EXCEPTION 'permissioned_as_email mismatch';
END IF;
IF job.kind IS DISTINCT FROM OLD.__job_kind THEN
RAISE EXCEPTION 'kind mismatch';
END IF;
IF job.runnable_id IS DISTINCT FROM OLD.__script_hash THEN
RAISE EXCEPTION 'runnable_id mismatch';
END IF;
IF job.runnable_path IS DISTINCT FROM OLD.__script_path THEN
RAISE EXCEPTION 'runnable_path mismatch';
END IF;
IF job.parent_job IS DISTINCT FROM OLD.__parent_job THEN
RAISE EXCEPTION 'parent_job mismatch';
END IF;
IF job.script_lang IS DISTINCT FROM OLD.__language THEN
RAISE EXCEPTION 'script_lang mismatch';
END IF;
IF job.script_entrypoint_override IS DISTINCT FROM NULLIF(OLD.__args->>'_ENTRYPOINT_OVERRIDE', '__WM_PREPROCESSOR')
AND OLD.__args->>'reason' IS DISTINCT FROM 'PREPROCESSOR_ARGS_ARE_DISCARDED'
THEN
RAISE EXCEPTION 'script_entrypoint_override mismatch';
END IF;
IF job.flow_step_id IS DISTINCT FROM OLD.__flow_step_id THEN
RAISE EXCEPTION 'flow_step_id mismatch';
END IF;
IF (job.flow_step_id IS NOT NULL) IS DISTINCT FROM OLD.__is_flow_step THEN
RAISE EXCEPTION 'is_flow_step mismatch';
END IF;
IF job.flow_innermost_root_job IS DISTINCT FROM OLD.__root_job THEN
RAISE EXCEPTION 'flow_innermost_root_job mismatch';
END IF;
IF job.trigger IS DISTINCT FROM OLD.__schedule_path THEN
RAISE EXCEPTION 'trigger mismatch';
END IF;
IF job.same_worker IS DISTINCT FROM OLD.__same_worker THEN
RAISE EXCEPTION 'same_worker mismatch';
END IF;
IF job.visible_to_owner IS DISTINCT FROM OLD.__visible_to_owner THEN
RAISE EXCEPTION 'visible_to_owner mismatch';
END IF;
IF job.concurrent_limit IS DISTINCT FROM OLD.__concurrent_limit THEN
RAISE EXCEPTION 'concurrent_limit mismatch';
END IF;
IF job.concurrency_time_window_s IS DISTINCT FROM OLD.__concurrency_time_window_s THEN
RAISE EXCEPTION 'concurrency_time_window_s mismatch';
END IF;
IF job.cache_ttl IS DISTINCT FROM OLD.__cache_ttl THEN
RAISE EXCEPTION 'cache_ttl mismatch';
END IF;
IF job.timeout IS DISTINCT FROM OLD.__timeout THEN
RAISE EXCEPTION 'timeout mismatch';
END IF;
IF job.priority IS DISTINCT FROM OLD.priority THEN
RAISE EXCEPTION 'priority mismatch';
END IF;
IF job.args::TEXT IS DISTINCT FROM OLD.__args::TEXT AND OLD.__args->>'_ENTRYPOINT_OVERRIDE' IS DISTINCT FROM '__WM_PREPROCESSOR' THEN
RAISE EXCEPTION 'args mismatch';
END IF;
IF job.pre_run_error IS DISTINCT FROM OLD.__pre_run_error THEN
RAISE EXCEPTION 'pre_run_error mismatch';
END IF;
-- v2_job_runtime:
SELECT * INTO job_runtime FROM v2_job_runtime WHERE id = OLD.id;
IF job_runtime.ping IS DISTINCT FROM OLD.__last_ping THEN
RAISE EXCEPTION 'ping mismatch';
END IF;
IF job_runtime.memory_peak IS DISTINCT FROM OLD.__mem_peak THEN
RAISE EXCEPTION 'memory_peak mismatch';
END IF;
-- v2_job_status:
IF EXISTS(SELECT 1 FROM v2_job_status WHERE id = OLD.id) THEN
SELECT * INTO job_status FROM v2_job_status WHERE id = OLD.id;
IF COALESCE(job_status.flow_status, job_status.workflow_as_code_status)::TEXT IS DISTINCT FROM OLD.__flow_status::TEXT
THEN
RAISE EXCEPTION 'flow_status mismatch';
END IF;
IF job_status.flow_leaf_jobs::TEXT IS DISTINCT FROM OLD.__leaf_jobs::TEXT THEN
RAISE EXCEPTION 'leaf_jobs mismatch';
END IF;
END IF;
RETURN OLD;
END $$ LANGUAGE PLPGSQL;
-- Apply phase 4:
DROP FUNCTION IF EXISTS v2_job_after_update CASCADE;
DROP FUNCTION IF EXISTS v2_job_completed_before_insert CASCADE;
DROP FUNCTION IF EXISTS v2_job_completed_before_update CASCADE;
DROP FUNCTION IF EXISTS v2_job_queue_after_insert CASCADE;
DROP FUNCTION IF EXISTS v2_job_queue_before_insert CASCADE;
DROP FUNCTION IF EXISTS v2_job_queue_before_update CASCADE;
DROP FUNCTION IF EXISTS v2_job_runtime_before_insert CASCADE;
DROP FUNCTION IF EXISTS v2_job_runtime_before_update CASCADE;
DROP FUNCTION IF EXISTS v2_job_status_before_insert CASCADE;
DROP FUNCTION IF EXISTS v2_job_status_before_update CASCADE;
CREATE OR REPLACE TRIGGER zzz_v2_job_queue_integrity_check_before_delete
BEFORE DELETE ON v2_job_queue
FOR EACH ROW
EXECUTE FUNCTION zzz_v2_job_queue_integrity_check();
DROP VIEW IF EXISTS completed_job, completed_job_view, job, queue, queue_view CASCADE;
-- TODO(uael): remove before phase 4
CREATE OR REPLACE FUNCTION zzz_v2_job_completed_integrity_check() RETURNS TRIGGER AS $$
DECLARE job v2_job;
BEGIN
IF (NEW.canceled_by IS NOT NULL) IS DISTINCT FROM NEW.__canceled THEN
RAISE EXCEPTION 'canceled mismatch';
END IF;
SELECT * INTO job FROM v2_job WHERE id = NEW.id;
IF job.tag IS DISTINCT FROM NEW.__tag THEN
RAISE EXCEPTION 'tag mismatch % %', job.tag, NEW.__tag;
END IF;
IF job.workspace_id IS DISTINCT FROM NEW.workspace_id THEN
RAISE EXCEPTION 'workspace_id mismatch';
END IF;
IF job.created_at IS DISTINCT FROM NEW.__created_at THEN
RAISE EXCEPTION 'created_at mismatch';
END IF;
IF job.created_by IS DISTINCT FROM NEW.__created_by THEN
RAISE EXCEPTION 'created_by mismatch';
END IF;
IF job.permissioned_as IS DISTINCT FROM NEW.__permissioned_as THEN
RAISE EXCEPTION 'permissioned_as mismatch';
END IF;
IF job.permissioned_as_email IS DISTINCT FROM NEW.__email THEN
RAISE EXCEPTION 'permissioned_as_email mismatch';
END IF;
IF job.kind IS DISTINCT FROM NEW.__job_kind THEN
RAISE EXCEPTION 'kind mismatch';
END IF;
IF job.runnable_id IS DISTINCT FROM NEW.__script_hash THEN
RAISE EXCEPTION 'runnable_id mismatch';
END IF;
IF job.runnable_path IS DISTINCT FROM NEW.__script_path THEN
RAISE EXCEPTION 'runnable_path mismatch';
END IF;
IF job.parent_job IS DISTINCT FROM NEW.__parent_job THEN
RAISE EXCEPTION 'parent_job mismatch';
END IF;
IF job.script_lang IS DISTINCT FROM NEW.__language THEN
RAISE EXCEPTION 'script_lang mismatch';
END IF;
IF job.script_entrypoint_override IS DISTINCT FROM NULLIF(NEW.__args->>'_ENTRYPOINT_OVERRIDE', '__WM_PREPROCESSOR')
AND NEW.__args->>'reason' IS DISTINCT FROM 'PREPROCESSOR_ARGS_ARE_DISCARDED'
THEN
RAISE EXCEPTION 'script_entrypoint_override mismatch';
END IF;
IF (job.flow_step_id IS NOT NULL) IS DISTINCT FROM NEW.__is_flow_step THEN
RAISE EXCEPTION 'is_flow_step mismatch';
END IF;
IF job.trigger IS DISTINCT FROM NEW.__schedule_path THEN
RAISE EXCEPTION 'trigger mismatch';
END IF;
IF job.visible_to_owner IS DISTINCT FROM NEW.__visible_to_owner THEN
RAISE EXCEPTION 'visible_to_owner mismatch';
END IF;
IF job.args::TEXT IS DISTINCT FROM NEW.__args::TEXT AND NEW.__args->>'_ENTRYPOINT_OVERRIDE' IS DISTINCT FROM '__WM_PREPROCESSOR' THEN
RAISE EXCEPTION 'args mismatch';
END IF;
RETURN NEW;
END $$ LANGUAGE PLPGSQL;
ALTER TABLE v2_job_queue
DROP COLUMN IF EXISTS __parent_job CASCADE,
DROP COLUMN IF EXISTS __created_by CASCADE,
DROP COLUMN IF EXISTS __script_hash CASCADE,
DROP COLUMN IF EXISTS __script_path CASCADE,
DROP COLUMN IF EXISTS __args CASCADE,
DROP COLUMN IF EXISTS __logs CASCADE,
DROP COLUMN IF EXISTS __raw_code CASCADE,
DROP COLUMN IF EXISTS __canceled CASCADE,
DROP COLUMN IF EXISTS __last_ping CASCADE,
DROP COLUMN IF EXISTS __job_kind CASCADE,
DROP COLUMN IF EXISTS __env_id CASCADE,
DROP COLUMN IF EXISTS __schedule_path CASCADE,
DROP COLUMN IF EXISTS __permissioned_as CASCADE,
DROP COLUMN IF EXISTS __flow_status CASCADE,
DROP COLUMN IF EXISTS __raw_flow CASCADE,
DROP COLUMN IF EXISTS __is_flow_step CASCADE,
DROP COLUMN IF EXISTS __language CASCADE,
DROP COLUMN IF EXISTS __same_worker CASCADE,
DROP COLUMN IF EXISTS __raw_lock CASCADE,
DROP COLUMN IF EXISTS __pre_run_error CASCADE,
DROP COLUMN IF EXISTS __email CASCADE,
DROP COLUMN IF EXISTS __visible_to_owner CASCADE,
DROP COLUMN IF EXISTS __mem_peak CASCADE,
DROP COLUMN IF EXISTS __root_job CASCADE,
DROP COLUMN IF EXISTS __leaf_jobs CASCADE,
DROP COLUMN IF EXISTS __concurrent_limit CASCADE,
DROP COLUMN IF EXISTS __concurrency_time_window_s CASCADE,
DROP COLUMN IF EXISTS __timeout CASCADE,
DROP COLUMN IF EXISTS __flow_step_id CASCADE,
DROP COLUMN IF EXISTS __cache_ttl CASCADE;
CREATE OR REPLACE TRIGGER zzz_v2_job_completed_integrity_check_after_insert
AFTER INSERT ON v2_job_completed
FOR EACH ROW
EXECUTE FUNCTION zzz_v2_job_completed_integrity_check();
LOCK TABLE v2_job_queue IN ACCESS EXCLUSIVE MODE;
ALTER TABLE v2_job_completed
DROP COLUMN IF EXISTS __parent_job CASCADE,
DROP COLUMN IF EXISTS __created_by CASCADE,
DROP COLUMN IF EXISTS __created_at CASCADE,
DROP COLUMN IF EXISTS __success CASCADE,
DROP COLUMN IF EXISTS __script_hash CASCADE,
DROP COLUMN IF EXISTS __script_path CASCADE,
DROP COLUMN IF EXISTS __args CASCADE,
DROP COLUMN IF EXISTS __logs CASCADE,
DROP COLUMN IF EXISTS __raw_code CASCADE,
DROP COLUMN IF EXISTS __canceled CASCADE,
DROP COLUMN IF EXISTS __job_kind CASCADE,
DROP COLUMN IF EXISTS __env_id CASCADE,
DROP COLUMN IF EXISTS __schedule_path CASCADE,
DROP COLUMN IF EXISTS __permissioned_as CASCADE,
DROP COLUMN IF EXISTS __raw_flow CASCADE,
DROP COLUMN IF EXISTS __is_flow_step CASCADE,
DROP COLUMN IF EXISTS __language CASCADE,
DROP COLUMN IF EXISTS __is_skipped CASCADE,
DROP COLUMN IF EXISTS __raw_lock CASCADE,
DROP COLUMN IF EXISTS __email CASCADE,
DROP COLUMN IF EXISTS __visible_to_owner CASCADE,
DROP COLUMN IF EXISTS __tag CASCADE,
DROP COLUMN IF EXISTS __priority CASCADE;

View File

@@ -4,8 +4,8 @@ INSERT INTO public.v2_job (
'1eecb96a-c8b0-4a3d-b1b6-087878c55e41', 'test-workspace', 'test-user', '2023-01-01 00:00:00', 'script', 'postgresql'
);
INSERT INTO public.completed_job (
id, workspace_id, created_by, created_at, duration_ms, success, flow_status, result, job_kind, language
INSERT INTO public.v2_job_completed (
id, workspace_id, duration_ms, status, result_columns, result
) VALUES (
'1eecb96a-c8b0-4a3d-b1b6-087878c55e41', 'test-workspace', 'test-user', '2023-01-01 00:00:00', 1000, true, '{"_metadata": {"column_order": ["b", "a"]}}', '[{"a": "second", "b": "first"}]', 'script', 'postgresql'
'1eecb96a-c8b0-4a3d-b1b6-087878c55e41', 'test-workspace', 1000, 'success'::job_status, '{b,a}', '[{"a": "second", "b": "first"}]'
)

View File

@@ -4005,11 +4005,6 @@ mod job_payload {
let args = job.args.as_ref().unwrap();
assert_eq!(args.get("foo"), Some(&json!("bar")));
assert_eq!(args.get("bar"), Some(&json!("baz")));
// TODO: remove this check on v2 phase 4
assert_eq!(
job.flow_status.as_ref().unwrap().get("_metadata"),
Some(&json!({"preprocessed_args": true}))
);
assert_eq!(job.json_result().unwrap(), json!("Hello bar baz"));
let job = sqlx::query!("SELECT preprocessed FROM v2_job WHERE id = $1", job.id)
.fetch_one(db)

View File

@@ -36,6 +36,7 @@ windmill-common = { workspace = true, default-features = false }
windmill-audit.workspace = true
windmill-parser.workspace = true
windmill-parser-ts.workspace = true
windmill-parser-py.workspace = true
windmill-git-sync.workspace = true
windmill-indexer = { workspace = true, optional = true }
tokio.workspace = true

View File

@@ -1,7 +1,7 @@
openapi: "3.0.3"
info:
version: 1.460.1
version: 1.463.4
title: Windmill API
contact:
@@ -1728,6 +1728,12 @@ paths:
type: string
slack_command_script:
type: string
teams_team_id:
type: string
teams_command_script:
type: string
teams_team_name:
type: string
auto_invite_domain:
type: string
auto_invite_operator:
@@ -1954,6 +1960,110 @@ paths:
schema:
type: string
/w/{workspace}/workspaces/edit_teams_command:
post:
summary: edit teams command
operationId: editTeamsCommand
tags:
- workspace
parameters:
- $ref: "#/components/parameters/WorkspaceId"
requestBody:
description: WorkspaceInvite
required: true
content:
application/json:
schema:
type: object
properties:
slack_command_script:
type: string
responses:
"200":
description: status
content:
text/plain:
schema:
type: string
/w/{workspace}/workspaces/available_teams_ids:
get:
summary: list available teams ids
operationId: listAvailableTeamsIds
tags:
- workspace
parameters:
- $ref: "#/components/parameters/WorkspaceId"
responses:
"200":
description: status
content:
application/json:
schema:
type: array
items:
type: object
properties:
team_name:
type: string
team_id:
type: string
/w/{workspace}/workspaces/available_teams_channels:
get:
summary: list available teams channels
operationId: listAvailableTeamsChannels
tags:
- workspace
parameters:
- $ref: "#/components/parameters/WorkspaceId"
responses:
"200":
description: status
content:
application/json:
schema:
type: array
items:
type: object
properties:
channel_name:
type: string
channel_id:
type: string
service_url:
type: string
tenant_id:
type: string
/w/{workspace}/workspaces/connect_teams:
post:
summary: connect teams
operationId: connectTeams
tags:
- workspace
parameters:
- $ref: "#/components/parameters/WorkspaceId"
requestBody:
description: connect teams
required: true
content:
application/json:
schema:
type: object
properties:
team_id:
type: string
team_name:
type: string
responses:
"200":
description: status
content:
text/plain:
schema:
type: string
/w/{workspace}/workspaces/run_slack_message_test_job:
post:
summary: run a job that sends a message to Slack
@@ -1987,6 +2097,40 @@ paths:
properties:
job_uuid:
type: string
/w/{workspace}/workspaces/run_teams_message_test_job:
post:
summary: run a job that sends a message to Teams
operationId: runTeamsMessageTestJob
tags:
- workspace
parameters:
- $ref: "#/components/parameters/WorkspaceId"
requestBody:
description: path to hub script to run and its corresponding args
required: true
content:
application/json:
schema:
type: object
properties:
hub_script_path:
type: string
channel:
type: string
test_msg:
type: string
responses:
"200":
description: status
content:
text/json:
schema:
type: object
properties:
job_uuid:
type: string
/w/{workspace}/workspaces/edit_deploy_to:
post:
@@ -3199,6 +3343,22 @@ paths:
schema:
type: string
/w/{workspace}/oauth/disconnect_teams:
post:
summary: disconnect teams
operationId: disconnectTeams
tags:
- oauth
parameters:
- $ref: "#/components/parameters/WorkspaceId"
responses:
"200":
description: disconnected teams
content:
text/plain:
schema:
type: string
/oauth/list_logins:
get:
summary: list oauth logins
@@ -3289,6 +3449,41 @@ paths:
items:
$ref: '#/components/schemas/TeamInfo'
/teams/activities:
post:
summary: send update to Microsoft Teams activity
description: Respond to a Microsoft Teams activity after a workspace command is run
operationId: sendMessageToConversation
tags:
- teams
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- conversation_id
- text
properties:
conversation_id:
type: string
description: The ID of the Teams conversation/activity
success:
type: boolean
description: Used for styling the card conditionally
default: true
text:
type: string
description: The message text to be sent in the Teams card
card_block:
type: object
description: The card block to be sent in the Teams card
responses:
'200':
description: Activity processed successfully
/w/{workspace}/resources/create:
post:
summary: create resource

View File

@@ -6,20 +6,21 @@
* LICENSE-AGPL for a copy of the license.
*/
use futures::FutureExt;
use sqlx::Executor;
use std::time::Duration;
use futures::FutureExt;
use sqlx::{
migrate::{Migrate, MigrateError},
pool::PoolConnection,
PgConnection, Pool, Postgres,
Executor, PgConnection, Pool, Postgres,
};
use windmill_audit::audit_ee::{AuditAuthor, AuditAuthorable};
use windmill_common::utils::generate_lock_id;
use windmill_common::{
db::{Authable, Authed},
error::Error,
};
use windmill_common::{utils::generate_lock_id, worker::MIN_VERSION_IS_AT_LEAST_1_461};
pub type DB = Pool<Postgres>;
@@ -224,6 +225,28 @@ pub async fn migrate(db: &DB) -> Result<(), Error> {
}
});
if !has_done_migration(db, "v2_finalize_disable_sync_III").await {
let db2 = db.clone();
let _ = tokio::task::spawn(async move {
loop {
if !*MIN_VERSION_IS_AT_LEAST_1_461.read().await {
tracing::info!("Waiting for all workers to be at least version 1.461 before applying v2 finalize migration, sleeping for 5s...");
tokio::time::sleep(Duration::from_secs(5)).await;
continue;
}
if let Err(err) = v2_finalize(&db2).await {
tracing::error!(
"{err:#}: Could not apply v2 finalize migration, retry in 30s.."
);
tokio::time::sleep(Duration::from_secs(30)).await;
continue;
}
tracing::info!("v2 finalization step successfully applied.");
break;
}
});
}
Ok(())
}
@@ -274,48 +297,51 @@ async fn fix_flow_versioning_migration(
Ok(())
}
async fn has_done_migration(db: &DB, migration_job_name: &str) -> bool {
sqlx::query_scalar!(
"SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = $1)",
migration_job_name
)
.fetch_one(db)
.await
.ok()
.flatten()
.unwrap_or(false)
}
macro_rules! run_windmill_migration {
($migration_job_name:expr, $db:expr, $code:block) => {
($migration_job_name:expr, $db:expr, |$tx:ident| $code:block) => {
{
let migration_job_name = $migration_job_name;
let db: &Pool<Postgres> = $db;
let has_done_migration = sqlx::query_scalar!(
"SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = $1)",
migration_job_name
)
.fetch_one(db)
.await?
.unwrap_or(false);
if !has_done_migration {
let has_done = has_done_migration(db, migration_job_name).await;
if !has_done {
tracing::info!("Applying {migration_job_name} migration");
let mut tx = db.begin().await?;
let mut $tx = db.begin().await?;
let mut r = false;
while !r {
r = sqlx::query_scalar!("SELECT pg_try_advisory_lock(4242)")
.fetch_one(&mut *tx)
.fetch_one(&mut *$tx)
.await
.map_err(|e| {
tracing::error!("Error acquiring {migration_job_name} lock: {e:#}");
sqlx::migrate::MigrateError::Execute(e)
})?
.unwrap_or(false);
if !r {
tracing::info!("PG {migration_job_name} lock already acquired by another server or worker, retrying in 5s. (look for the advisory lock in pg_lock with granted = true)");
drop($tx);
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
$tx = db.begin().await?;
}
}
tracing::info!("acquired lock for {migration_job_name}");
let has_done_migration = sqlx::query_scalar!(
"SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = $1)",
migration_job_name
)
.fetch_one(db)
.await?
.unwrap_or(false);
let has_done = has_done_migration(db, migration_job_name).await;
if !has_done_migration {
if !has_done {
$code
@@ -323,7 +349,7 @@ macro_rules! run_windmill_migration {
"INSERT INTO windmill_migrations (name) VALUES ($1) ON CONFLICT DO NOTHING",
migration_job_name
)
.execute(&mut *tx)
.execute(&mut *$tx)
.await?;
tracing::info!("Finished applying {migration_job_name} migration");
} else {
@@ -331,9 +357,9 @@ macro_rules! run_windmill_migration {
}
let _ = sqlx::query("SELECT pg_advisory_unlock(4242)")
.execute(&mut *tx)
.execute(&mut *$tx)
.await?;
tx.commit().await?;
$tx.commit().await?;
tracing::info!("released lock for {migration_job_name}");
} else {
tracing::debug!("migration {migration_job_name} already done");
@@ -343,6 +369,102 @@ macro_rules! run_windmill_migration {
};
}
async fn v2_finalize(db: &DB) -> Result<(), Error> {
run_windmill_migration!("v2_finalize_disable_sync_III", db, |tx| {
tx.execute(
r#"
ALTER TABLE v2_job_queue DISABLE ROW LEVEL SECURITY;
ALTER TABLE v2_job_completed DISABLE ROW LEVEL SECURITY;
DROP FUNCTION IF EXISTS v2_job_after_update CASCADE;
DROP FUNCTION IF EXISTS v2_job_completed_before_insert CASCADE;
DROP FUNCTION IF EXISTS v2_job_completed_before_update CASCADE;
DROP FUNCTION IF EXISTS v2_job_queue_after_insert CASCADE;
DROP FUNCTION IF EXISTS v2_job_queue_before_insert CASCADE;
DROP FUNCTION IF EXISTS v2_job_queue_before_update CASCADE;
DROP FUNCTION IF EXISTS v2_job_runtime_before_insert CASCADE;
DROP FUNCTION IF EXISTS v2_job_runtime_before_update CASCADE;
DROP FUNCTION IF EXISTS v2_job_status_before_insert CASCADE;
DROP FUNCTION IF EXISTS v2_job_status_before_update CASCADE;
DROP VIEW IF EXISTS completed_job, completed_job_view, job, queue, queue_view CASCADE;
"#,
)
.await?;
});
run_windmill_migration!("v2_finalize_job_queue", db, |tx| {
tx.execute(
r#"
ALTER TABLE v2_job_queue
DROP COLUMN IF EXISTS __parent_job CASCADE,
DROP COLUMN IF EXISTS __created_by CASCADE,
DROP COLUMN IF EXISTS __script_hash CASCADE,
DROP COLUMN IF EXISTS __script_path CASCADE,
DROP COLUMN IF EXISTS __args CASCADE,
DROP COLUMN IF EXISTS __logs CASCADE,
DROP COLUMN IF EXISTS __raw_code CASCADE,
DROP COLUMN IF EXISTS __canceled CASCADE,
DROP COLUMN IF EXISTS __last_ping CASCADE,
DROP COLUMN IF EXISTS __job_kind CASCADE,
DROP COLUMN IF EXISTS __env_id CASCADE,
DROP COLUMN IF EXISTS __schedule_path CASCADE,
DROP COLUMN IF EXISTS __permissioned_as CASCADE,
DROP COLUMN IF EXISTS __flow_status CASCADE,
DROP COLUMN IF EXISTS __raw_flow CASCADE,
DROP COLUMN IF EXISTS __is_flow_step CASCADE,
DROP COLUMN IF EXISTS __language CASCADE,
DROP COLUMN IF EXISTS __same_worker CASCADE,
DROP COLUMN IF EXISTS __raw_lock CASCADE,
DROP COLUMN IF EXISTS __pre_run_error CASCADE,
DROP COLUMN IF EXISTS __email CASCADE,
DROP COLUMN IF EXISTS __visible_to_owner CASCADE,
DROP COLUMN IF EXISTS __mem_peak CASCADE,
DROP COLUMN IF EXISTS __root_job CASCADE,
DROP COLUMN IF EXISTS __leaf_jobs CASCADE,
DROP COLUMN IF EXISTS __concurrent_limit CASCADE,
DROP COLUMN IF EXISTS __concurrency_time_window_s CASCADE,
DROP COLUMN IF EXISTS __timeout CASCADE,
DROP COLUMN IF EXISTS __flow_step_id CASCADE,
DROP COLUMN IF EXISTS __cache_ttl CASCADE;
"#,
)
.await?;
});
run_windmill_migration!("v2_finalize_job_completed", db, |tx| {
tx.execute(
r#"
ALTER TABLE v2_job_completed
DROP COLUMN IF EXISTS __parent_job CASCADE,
DROP COLUMN IF EXISTS __created_by CASCADE,
DROP COLUMN IF EXISTS __created_at CASCADE,
DROP COLUMN IF EXISTS __success CASCADE,
DROP COLUMN IF EXISTS __script_hash CASCADE,
DROP COLUMN IF EXISTS __script_path CASCADE,
DROP COLUMN IF EXISTS __args CASCADE,
DROP COLUMN IF EXISTS __logs CASCADE,
DROP COLUMN IF EXISTS __raw_code CASCADE,
DROP COLUMN IF EXISTS __canceled CASCADE,
DROP COLUMN IF EXISTS __job_kind CASCADE,
DROP COLUMN IF EXISTS __env_id CASCADE,
DROP COLUMN IF EXISTS __schedule_path CASCADE,
DROP COLUMN IF EXISTS __permissioned_as CASCADE,
DROP COLUMN IF EXISTS __raw_flow CASCADE,
DROP COLUMN IF EXISTS __is_flow_step CASCADE,
DROP COLUMN IF EXISTS __language CASCADE,
DROP COLUMN IF EXISTS __is_skipped CASCADE,
DROP COLUMN IF EXISTS __raw_lock CASCADE,
DROP COLUMN IF EXISTS __email CASCADE,
DROP COLUMN IF EXISTS __visible_to_owner CASCADE,
DROP COLUMN IF EXISTS __tag CASCADE,
DROP COLUMN IF EXISTS __priority CASCADE;
"#,
)
.await?;
});
Ok(())
}
async fn fix_job_completed_index(db: &DB) -> Result<(), Error> {
// let has_done_migration = sqlx::query_scalar!(
// "SELECT EXISTS(SELECT name FROM windmill_migrations WHERE name = 'fix_job_completed_index')"
@@ -385,7 +507,7 @@ async fn fix_job_completed_index(db: &DB) -> Result<(), Error> {
// tx.commit().await?;
// }
run_windmill_migration!("fix_job_completed_index_2", &db, {
run_windmill_migration!("fix_job_completed_index_2", &db, |tx| {
// sqlx::query(
// "CREATE INDEX CONCURRENTLY IF NOT EXISTS ix_completed_job_workspace_id_created_at_new_2 ON completed_job (workspace_id, job_kind, success, is_skipped, is_flow_step, created_at DESC)"
// ).execute(db).await?;
@@ -405,7 +527,7 @@ async fn fix_job_completed_index(db: &DB) -> Result<(), Error> {
.await?;
});
run_windmill_migration!("fix_job_completed_index_3", &db, {
run_windmill_migration!("fix_job_completed_index_3", &db, |tx| {
sqlx::query("DROP INDEX CONCURRENTLY IF EXISTS index_completed_job_on_schedule_path")
.execute(db)
.await?;
@@ -423,8 +545,8 @@ async fn fix_job_completed_index(db: &DB) -> Result<(), Error> {
.await?;
});
run_windmill_migration!("fix_job_index_1", &db, {
let migration_job_name = "fix_job_completed_index_4";
run_windmill_migration!("fix_job_index_1_II", &db, |tx| {
let migration_job_name = "fix_job_index_1_II";
let mut i = 1;
tracing::info!("step {i} of {migration_job_name} migration");
sqlx::query!("create index concurrently if not exists ix_job_workspace_id_created_at_new_3 ON v2_job (workspace_id, created_at DESC)")
@@ -451,31 +573,26 @@ async fn fix_job_completed_index(db: &DB) -> Result<(), Error> {
i += 1;
tracing::info!("step {i} of {migration_job_name} migration");
sqlx::query!("create index concurrently if not exists ix_job_workspace_id_created_at_new_6 ON v2_job (workspace_id, created_at DESC) where kind in ('script', 'flow') AND parent_job IS NULL")
.execute(db)
.await?;
i += 1;
tracing::info!("step {i} of {migration_job_name} migration");
sqlx::query!("create index concurrently if not exists ix_job_workspace_id_created_at_new_7 ON v2_job (workspace_id, created_at DESC) where kind in ('script', 'flow') AND parent_job IS NULL")
.execute(db)
.await?;
i += 1;
tracing::info!("step {i} of {migration_job_name} migration");
sqlx::query!("create index concurrently if not exists ix_completed_job_workspace_id_started_at_new_2 ON v2_job_completed (workspace_id, started_at DESC)")
.execute(db)
.await?;
i += 1;
tracing::info!("step {i} of {migration_job_name} migration");
sqlx::query!("create index concurrently if not exists root_job_index_by_path_2 ON v2_job (workspace_id, runnable_path, created_at desc) WHERE parent_job IS NULL")
sqlx::query!("create index concurrently if not exists ix_job_root_job_index_by_path_2 ON v2_job (workspace_id, runnable_path, created_at desc) WHERE parent_job IS NULL")
.execute(db)
.await?;
i += 1;
tracing::info!("step {i} of {migration_job_name} migration");
sqlx::query!("DROP INDEX CONCURRENTLY IF EXISTS root_job_index_by_path_2")
.execute(db)
.await?;
i += 1;
tracing::info!("step {i} of {migration_job_name} migration");
sqlx::query!("create index concurrently if not exists ix_job_created_at ON v2_job (created_at DESC)")
.execute(db)
.await?;
@@ -504,7 +621,7 @@ async fn fix_job_completed_index(db: &DB) -> Result<(), Error> {
.await?;
});
run_windmill_migration!("fix_labeled_jobs_index", &db, {
run_windmill_migration!("fix_labeled_jobs_index", &db, |tx| {
tracing::info!("Special migration to add index concurrently on job labels 2");
sqlx::query!("DROP INDEX CONCURRENTLY IF EXISTS labeled_jobs_on_jobs")
.execute(db)
@@ -514,7 +631,7 @@ async fn fix_job_completed_index(db: &DB) -> Result<(), Error> {
).execute(db).await?;
});
run_windmill_migration!("v2_labeled_jobs_index", &db, {
run_windmill_migration!("v2_labeled_jobs_index", &db, |tx| {
tracing::info!("Special migration to add index concurrently on job labels");
sqlx::query!(
"CREATE INDEX CONCURRENTLY ix_v2_job_labels ON v2_job
@@ -525,6 +642,43 @@ async fn fix_job_completed_index(db: &DB) -> Result<(), Error> {
.await?;
});
run_windmill_migration!("v2_jobs_rls", &db, |tx| {
sqlx::query!("ALTER TABLE v2_job ENABLE ROW LEVEL SECURITY")
.execute(db)
.await?;
});
run_windmill_migration!("v2_improve_v2_job_indices_ii", &db, |tx| {
sqlx::query!("create index concurrently if not exists ix_v2_job_workspace_id_created_at ON v2_job (workspace_id, created_at DESC) where kind in ('script', 'flow', 'singlescriptflow') AND parent_job IS NULL")
.execute(db)
.await?;
sqlx::query!("DROP INDEX CONCURRENTLY IF EXISTS ix_job_workspace_id_created_at_new_6")
.execute(db)
.await?;
sqlx::query!("DROP INDEX CONCURRENTLY IF EXISTS ix_job_workspace_id_created_at_new_7")
.execute(db)
.await?;
});
run_windmill_migration!("v2_improve_v2_queued_jobs_indices", &db, |tx| {
sqlx::query!("CREATE INDEX CONCURRENTLY queue_sort_v2 ON v2_job_queue (priority DESC NULLS LAST, scheduled_for, tag) WHERE running = false")
.execute(db)
.await?;
// sqlx::query!("CREATE INDEX CONCURRENTLY queue_sort_2_v2 ON v2_job_queue (tag, priority DESC NULLS LAST, scheduled_for) WHERE running = false")
// .execute(db)
// .await?;
sqlx::query!("DROP INDEX CONCURRENTLY IF EXISTS queue_sort")
.execute(db)
.await?;
sqlx::query!("DROP INDEX CONCURRENTLY IF EXISTS queue_sort_2")
.execute(db)
.await?;
});
Ok(())
}

View File

@@ -538,7 +538,7 @@ async fn get_http_route_trigger(
let route_path = trigger.route_path.clone();
if trigger.is_static_website {
router
.insert(format!("{}/*wm_subpath", route_path), idx)
.insert(format!("/{}/*wm_subpath", route_path), idx)
.unwrap_or_else(|e| {
tracing::warn!(
"Failed to consider http trigger route {}: {:?}",
@@ -547,19 +547,22 @@ async fn get_http_route_trigger(
);
});
}
router.insert(route_path.as_str(), idx).unwrap_or_else(|e| {
tracing::warn!(
"Failed to consider http trigger route {}: {:?}",
route_path,
e,
);
});
router
.insert(format!("/{}", route_path), idx)
.unwrap_or_else(|e| {
tracing::warn!(
"Failed to consider http trigger route {}: {:?}",
route_path,
e,
);
});
}
let trigger_idx = router.at(route_path.0.as_str()).ok();
let requested_path = format!("/{}", route_path.0);
let trigger_idx = router.at(requested_path.as_str()).ok();
let matchit::Match { value: trigger_idx, params } =
not_found_if_none(trigger_idx, "Trigger", route_path.0.as_str())?;
not_found_if_none(trigger_idx, "Trigger", requested_path.as_str())?;
let trigger = triggers.remove(trigger_idx.to_owned());

View File

@@ -82,9 +82,9 @@ impl RunnableType {
fn column_name(&self) -> &'static str {
match self {
RunnableType::ScriptHash => "script_hash",
RunnableType::ScriptPath => "script_path",
RunnableType::FlowPath => "script_path",
RunnableType::ScriptHash => "runnable_id",
RunnableType::ScriptPath => "runnable_path",
RunnableType::FlowPath => "runnable_path",
}
}
}
@@ -133,9 +133,9 @@ async fn get_input_history(
let mut tx = user_db.begin(&authed).await?;
let sql = &format!(
"select id, created_at, created_by, 'null'::jsonb as args, success from v2_as_completed_job \
where {} = $1 and job_kind = any($2) and workspace_id = $3 \
order by created_at desc limit $4 offset $5",
"select id, v2_job.created_at, created_by, 'null'::jsonb as args, status = 'success' as success from v2_job JOIN v2_job_completed USING (id) \
where {} = $1 and kind = any($2) and v2_job.workspace_id = $3 AND v2_job_completed.status != 'skipped' \
order by v2_job.created_at desc limit $4 offset $5",
r.runnable_type.column_name()
);

View File

@@ -717,7 +717,12 @@ macro_rules! get_job_query {
const_format::formatcp!(
"SELECT \
id, {table}.workspace_id, parent_job, created_by, {table}.created_at, started_at, script_hash, script_path, \
CASE WHEN args is null or pg_column_size(args) < 90000 THEN args ELSE '{{\"reason\": \"WINDMILL_TOO_BIG\"}}'::jsonb END as args, \
CASE WHEN args is null THEN NULL
WHEN pg_column_size(args) < 90000 THEN
CASE WHEN jsonb_typeof(args) = 'object' THEN args
ELSE jsonb_build_object('value', args)
END
ELSE '{{\"reason\": \"WINDMILL_TOO_BIG\"}}'::jsonb END as args, \
{logs} as logs, {code} as raw_code, canceled, canceled_by, canceled_reason, job_kind, \
schedule_path, permissioned_as, flow_status, {flow} as raw_flow, is_flow_step, language, \
{lock} as raw_lock, email, visible_to_owner, mem_peak, tag, priority, preprocessed, {additional_fields} \
@@ -1156,7 +1161,7 @@ pub struct ListableCompletedJob {
pub parent_job: Option<Uuid>,
pub created_by: String,
pub created_at: chrono::DateTime<chrono::Utc>,
pub started_at: chrono::DateTime<chrono::Utc>,
pub started_at: Option<chrono::DateTime<chrono::Utc>>,
pub duration_ms: i64,
pub success: bool,
#[serde(skip_serializing_if = "Option::is_none")]
@@ -1294,27 +1299,30 @@ pub fn filter_list_queue_query(
w_id: &str,
join_outstanding_wait_times: bool,
) -> SqlBuilder {
sqlb.join("v2_job").on_eq("v2_job_queue.id", "v2_job.id");
if join_outstanding_wait_times {
sqlb.left()
.join("outstanding_wait_time")
.on_eq("id", "outstanding_wait_time.job_id");
.on_eq("v2_job.id", "outstanding_wait_time.job_id");
}
if w_id != "admins" || !lq.all_workspaces.is_some_and(|x| x) {
sqlb.and_where_eq("workspace_id", "?".bind(&w_id));
sqlb.and_where_eq("v2_job.workspace_id", "?".bind(&w_id));
}
if let Some(ps) = &lq.script_path_start {
sqlb.and_where_like_left("script_path", ps);
sqlb.and_where_like_left("runnable_path", ps);
}
if let Some(p) = &lq.script_path_exact {
sqlb.and_where_eq("script_path", "?".bind(p));
sqlb.and_where_eq("runnable_path", "?".bind(p));
}
if let Some(p) = &lq.schedule_path {
sqlb.and_where_eq("schedule_path", "?".bind(p));
sqlb.and_where_eq("trigger", "?".bind(p));
sqlb.and_where_eq("trigger_kind", "'schedule'");
}
if let Some(h) = &lq.script_hash {
sqlb.and_where_eq("script_hash", "?".bind(h));
sqlb.and_where_eq("runnable_id", "?".bind(h));
}
if let Some(cb) = &lq.created_by {
sqlb.and_where_eq("created_by", "?".bind(cb));
@@ -1335,7 +1343,11 @@ pub fn filter_list_queue_query(
sqlb.and_where_ge("started_at", "?".bind(&dt.to_rfc3339()));
}
if let Some(fs) = &lq.is_flow_step {
sqlb.and_where_eq("is_flow_step", fs);
if *fs {
sqlb.and_where_is_not_null("flow_step_id");
} else {
sqlb.and_where_is_null("flow_step_id");
}
}
if let Some(fs) = &lq.has_null_parent {
if *fs {
@@ -1344,20 +1356,20 @@ pub fn filter_list_queue_query(
}
if let Some(dt) = &lq.created_before {
sqlb.and_where_le("created_at", "?".bind(&dt.to_rfc3339()));
sqlb.and_where_le("v2_job.created_at", "?".bind(&dt.to_rfc3339()));
}
if let Some(dt) = &lq.created_after {
sqlb.and_where_ge("created_at", "?".bind(&dt.to_rfc3339()));
sqlb.and_where_ge("v2_job.created_at", "?".bind(&dt.to_rfc3339()));
}
if let Some(dt) = &lq.created_or_started_after {
let ts = dt.timestamp_millis();
sqlb.and_where(format!("(started_at IS NOT NULL AND started_at >= to_timestamp({} / 1000.0)) OR (started_at IS NULL AND created_at >= to_timestamp({} / 1000.0))", ts, ts));
sqlb.and_where(format!("(started_at IS NOT NULL AND started_at >= to_timestamp({} / 1000.0)) OR (started_at IS NULL AND v2_job.created_at >= to_timestamp({} / 1000.0))", ts, ts));
}
if let Some(dt) = &lq.created_or_started_before {
let ts = dt.timestamp_millis();
sqlb.and_where(format!("(started_at IS NOT NULL AND started_at < to_timestamp({} / 1000.0)) OR (started_at IS NULL AND created_at < to_timestamp({} / 1000.0))", ts, ts));
sqlb.and_where(format!("(started_at IS NOT NULL AND started_at < to_timestamp({} / 1000.0)) OR (started_at IS NULL AND v2_job.created_at < to_timestamp({} / 1000.0))", ts, ts));
}
if let Some(s) = &lq.suspended {
@@ -1370,7 +1382,7 @@ pub fn filter_list_queue_query(
if let Some(jk) = &lq.job_kinds {
sqlb.and_where_in(
"job_kind",
"kind",
&jk.split(',').into_iter().map(quote).collect::<Vec<_>>(),
);
}
@@ -1384,7 +1396,8 @@ pub fn filter_list_queue_query(
}
if lq.is_not_schedule.unwrap_or(false) {
sqlb.and_where("schedule_path IS null");
sqlb.and_where("trigger_kind != 'schedule'")
.or_where("trigger_kind IS NULL");
}
sqlb
@@ -1399,9 +1412,9 @@ pub fn list_queue_jobs_query(
tags: Option<Vec<&str>>,
) -> SqlBuilder {
let (limit, offset) = paginate_without_limits(pagination);
let mut sqlb = SqlBuilder::select_from("v2_as_queue")
let mut sqlb = SqlBuilder::select_from("v2_job_queue")
.fields(fields)
.order_by("created_at", lq.order_desc.unwrap_or(true))
.order_by("v2_job.created_at", lq.order_desc.unwrap_or(true))
.limit(limit)
.offset(offset)
.clone();
@@ -1446,26 +1459,25 @@ async fn list_queue_jobs(
&w_id,
&lq,
&[
"id",
"running",
"created_by",
"created_at",
"started_at",
"scheduled_for",
"script_hash",
"script_path",
"v2_job.id",
"v2_job_queue.running",
"v2_job.created_by",
"v2_job.created_at",
"v2_job_queue.started_at",
"v2_job_queue.scheduled_for",
"v2_job.runnable_id as script_hash",
"v2_job.runnable_path as script_path",
"null as args",
"job_kind",
"schedule_path",
"permissioned_as",
"is_flow_step",
"language",
"same_worker",
"email",
"suspend",
"tag",
"priority",
"workspace_id",
"v2_job.kind as job_kind",
"CASE WHEN v2_job.trigger_kind = 'schedule' THEN v2_job.trigger END as schedule_path",
"v2_job.permissioned_as",
"v2_job.flow_step_id IS NOT NULL as is_flow_step",
"v2_job.script_lang as language",
"v2_job.permissioned_as_email as email",
"v2_job_queue.suspend",
"v2_job.tag",
"v2_job.priority",
"v2_job.workspace_id",
],
pagination,
false,
@@ -1605,13 +1617,14 @@ async fn list_filtered_uuids(
) -> error::JsonResult<Vec<Uuid>> {
require_admin(authed.is_admin, &authed.username)?;
let mut sqlb = SqlBuilder::select_from("v2_as_queue")
.fields(&["id"])
let mut sqlb = SqlBuilder::select_from("v2_job_queue")
.fields(&["v2_job_queue.id"])
.clone();
sqlb = join_concurrency_key(lq.concurrency_key.as_ref(), sqlb);
sqlb.and_where_is_null("schedule_path");
sqlb.and_where_ne("v2_job.trigger_kind", "'schedule'")
.or_where_is_null("v2_job.trigger_kind");
if let Some(tags) = get_scope_tags(&authed) {
sqlb.and_where_in("tag", &tags.iter().map(|x| quote(x)).collect::<Vec<_>>());
@@ -1625,7 +1638,7 @@ async fn list_filtered_uuids(
Ok(Json(jobs))
}
#[derive(Serialize, Debug, FromRow)]
#[derive(Serialize)]
struct QueueStats {
database_length: i64,
suspended: Option<i64>,
@@ -1634,6 +1647,7 @@ struct QueueStats {
#[derive(Deserialize)]
pub struct CountQueueJobsQuery {
all_workspaces: Option<bool>,
tags: Option<String>,
}
async fn count_queue_jobs(
@@ -1641,12 +1655,16 @@ async fn count_queue_jobs(
Path(w_id): Path<String>,
Query(cq): Query<CountQueueJobsQuery>,
) -> error::JsonResult<QueueStats> {
let tags = cq
.tags
.map(|t| t.split(',').map(|s| s.to_string()).collect::<Vec<_>>());
Ok(Json(
sqlx::query_as!(
QueueStats,
"SELECT coalesce(COUNT(*) FILTER(WHERE suspend = 0 AND running = false), 0) as \"database_length!\", coalesce(COUNT(*) FILTER(WHERE suspend > 0), 0) as \"suspended!\" FROM v2_as_queue WHERE (workspace_id = $1 OR $2) AND scheduled_for <= now()",
"SELECT coalesce(COUNT(*) FILTER(WHERE suspend = 0 AND running = false), 0) as \"database_length!\", coalesce(COUNT(*) FILTER(WHERE suspend > 0), 0) as \"suspended!\" FROM v2_as_queue WHERE (workspace_id = $1 OR $2) AND scheduled_for <= now() AND ($3::text[] IS NULL OR tag = ANY($3))",
w_id,
w_id == "admins" && cq.all_workspaces.unwrap_or(false),
tags.as_ref().map(|v| v.as_slice())
)
.fetch_one(&db)
.await?,
@@ -1666,23 +1684,28 @@ async fn count_completed_jobs_detail(
Path(w_id): Path<String>,
Query(query): Query<CountCompletedJobsQuery>,
) -> error::JsonResult<i64> {
let mut sqlb = SqlBuilder::select_from("v2_as_completed_job");
let mut sqlb = SqlBuilder::select_from("v2_job_completed");
//FOR RLS
sqlb.join("v2_job USING (id)");
sqlb.field("COUNT(*) as count");
if !query.all_workspaces.unwrap_or(false) {
sqlb.and_where_eq("workspace_id", "?".bind(&w_id));
sqlb.and_where_eq("v2_job.workspace_id", "?".bind(&w_id));
}
if let Some(after_s_ago) = query.completed_after_s_ago {
let after = Utc::now() - chrono::Duration::seconds(after_s_ago);
sqlb.and_where_gt(
"started_at + duration_ms / 1000 * interval '1 second'",
"?".bind(&after.to_rfc3339()),
);
sqlb.and_where_gt("ended_at", "?".bind(&after.to_rfc3339()));
}
if let Some(success) = query.success {
sqlb.and_where_eq("success", "?".bind(&success));
if success {
sqlb.and_where_eq("status", "'success'")
.or_where_eq("status", "'skipped'");
} else {
sqlb.and_where_ne("status", "'success'")
.and_where_ne("status", "'skipped'");
}
}
if let Some(tags) = query.tags {
@@ -1782,13 +1805,13 @@ async fn list_jobs(
}
sqlc.unwrap().limit(per_page).offset(offset).query()?
};
let mut tx = user_db.begin(&authed).await?;
let mut tx: Transaction<'_, Postgres> = user_db.begin(&authed).await?;
#[cfg(feature = "prometheus")]
let start = Instant::now();
#[cfg(feature = "prometheus")]
if _api_list_jobs_query_duration.is_some() {
if _api_list_jobs_query_duration.is_some() || true {
tracing::info!("list_jobs query: {}", sql);
}
@@ -2651,77 +2674,78 @@ pub struct UnifiedJob {
const CJ_FIELDS: &[&str] = &[
"'CompletedJob' as typ",
"id",
"workspace_id",
"parent_job",
"created_by",
"created_at",
"started_at",
"v2_job.id",
"v2_job.workspace_id",
"v2_job.parent_job",
"v2_job.created_by",
"v2_job.created_at",
"v2_job_completed.started_at",
"null as scheduled_for",
"null as running",
"script_hash",
"script_path",
"v2_job.runnable_id as script_hash",
"v2_job.runnable_path as script_path",
"null as args",
"duration_ms",
"success",
"deleted",
"canceled",
"canceled_by",
"job_kind",
"schedule_path",
"permissioned_as",
"is_flow_step",
"language",
"is_skipped",
"email",
"visible_to_owner",
"v2_job_completed.duration_ms",
"v2_job_completed.status = 'success' OR v2_job_completed.status = 'skipped' as success",
"false as deleted",
"v2_job_completed.status = 'canceled' as canceled",
"v2_job_completed.canceled_by",
"v2_job.kind as job_kind",
"CASE WHEN v2_job.trigger_kind = 'schedule' THEN v2_job.trigger END as schedule_path",
"v2_job.permissioned_as",
"v2_job.flow_step_id IS NOT NULL as is_flow_step",
"v2_job.script_lang as language",
"v2_job_completed.status = 'skipped' as is_skipped",
"v2_job.permissioned_as_email as email",
"v2_job.visible_to_owner",
"null as suspend",
"mem_peak",
"tag",
"v2_job_completed.memory_peak as mem_peak",
"v2_job.tag",
"null as concurrent_limit",
"null as concurrency_time_window_s",
"priority",
"result->'wm_labels' as labels",
"v2_job.priority",
"v2_job_completed.result->'wm_labels' as labels",
"self_wait_time_ms",
"aggregate_wait_time_ms",
"preprocessed",
"v2_job.preprocessed",
];
const QJ_FIELDS: &[&str] = &[
"'QueuedJob' as typ",
"id",
"workspace_id",
"parent_job",
"created_by",
"created_at",
"started_at",
"scheduled_for",
"running",
"script_hash",
"script_path",
"v2_job.id",
"v2_job.workspace_id",
"v2_job.parent_job",
"v2_job.created_by",
"v2_job.created_at",
"v2_job_queue.started_at",
"v2_job_queue.scheduled_for",
"v2_job_queue.running",
"v2_job.runnable_id as script_hash",
"v2_job.runnable_path as script_path",
"null as args",
"null as duration_ms",
"null as success",
"false as deleted",
"canceled",
"canceled_by",
"job_kind",
"schedule_path",
"permissioned_as",
"is_flow_step",
"language",
"v2_job_queue.canceled_by IS NOT NULL as canceled",
"v2_job_queue.canceled_by",
"v2_job.kind as job_kind",
"CASE WHEN v2_job.trigger_kind = 'schedule' THEN v2_job.trigger END as schedule_path",
"v2_job.permissioned_as",
"v2_job.flow_step_id IS NOT NULL as is_flow_step",
"v2_job.script_lang as language",
"false as is_skipped",
"email",
"visible_to_owner",
"suspend",
"mem_peak",
"tag",
"concurrent_limit",
"concurrency_time_window_s",
"priority",
"v2_job.permissioned_as_email as email",
"v2_job.visible_to_owner",
"v2_job_queue.suspend",
"null as mem_peak",
"v2_job.tag",
"v2_job.concurrent_limit",
"v2_job.concurrency_time_window_s",
"v2_job.priority",
"null as labels",
"self_wait_time_ms",
"aggregate_wait_time_ms",
"preprocessed",
"v2_job.preprocessed",
];
impl UnifiedJob {
@@ -4676,6 +4700,7 @@ struct BatchInfo {
flow_value: Option<FlowValue>,
path: Option<String>,
rawscript: Option<BatchRawScript>,
tag: Option<String>,
}
#[tracing::instrument(level = "trace", skip_all)]
@@ -4844,6 +4869,8 @@ async fn add_batch_jobs(
} else {
format!("{}", language.as_str())
}
} else if let Some(tag) = batch_info.tag {
tag
} else {
format!("{}", language.as_str())
};
@@ -5253,10 +5280,13 @@ pub fn filter_list_completed_query(
w_id: &str,
join_outstanding_wait_times: bool,
) -> SqlBuilder {
sqlb.join("v2_job")
.on_eq("v2_job_completed.id", "v2_job.id");
if join_outstanding_wait_times {
sqlb.left()
.join("outstanding_wait_time")
.on_eq("id", "outstanding_wait_time.job_id");
.on_eq("v2_job.id", "outstanding_wait_time.job_id");
}
if let Some(label) = &lq.label {
@@ -5267,21 +5297,22 @@ pub fn filter_list_completed_query(
}
if w_id != "admins" || !lq.all_workspaces.is_some_and(|x| x) {
sqlb.and_where_eq("workspace_id", "?".bind(&w_id));
sqlb.and_where_eq("v2_job.workspace_id", "?".bind(&w_id));
}
if let Some(p) = &lq.schedule_path {
sqlb.and_where_eq("schedule_path", "?".bind(p));
sqlb.and_where_eq("trigger", "?".bind(p));
sqlb.and_where_eq("trigger_kind", "'schedule'");
}
if let Some(ps) = &lq.script_path_start {
sqlb.and_where_like_left("script_path", ps);
sqlb.and_where_like_left("runnable_path", ps);
}
if let Some(p) = &lq.script_path_exact {
sqlb.and_where_eq("script_path", "?".bind(p));
sqlb.and_where_eq("runnable_path", "?".bind(p));
}
if let Some(h) = &lq.script_hash {
sqlb.and_where_eq("script_hash", "?".bind(h));
sqlb.and_where_eq("runnable_id", "?".bind(h));
}
if let Some(t) = &lq.tag {
sqlb.and_where_eq("tag", "?".bind(t));
@@ -5290,7 +5321,13 @@ pub fn filter_list_completed_query(
sqlb.and_where_eq("created_by", "?".bind(cb));
}
if let Some(r) = &lq.success {
sqlb.and_where_eq("success", r);
if *r {
sqlb.and_where_eq("status", "'success'")
.or_where_eq("status", "'skipped'");
} else {
sqlb.and_where_eq("status", "'failure'")
.or_where_eq("status", "'canceled'");
}
}
if let Some(pj) = &lq.parent_job {
sqlb.and_where_eq("parent_job", "?".bind(pj));
@@ -5321,10 +5358,18 @@ pub fn filter_list_completed_query(
}
if let Some(sk) = &lq.is_skipped {
sqlb.and_where_eq("is_skipped", sk);
if *sk {
sqlb.and_where_eq("status", "'skipped'");
} else {
sqlb.and_where_ne("status", "'skipped'");
}
}
if let Some(fs) = &lq.is_flow_step {
sqlb.and_where_eq("is_flow_step", fs);
if *fs {
sqlb.and_where_is_not_null("flow_step_id");
} else {
sqlb.and_where_is_null("flow_step_id");
}
}
if let Some(fs) = &lq.has_null_parent {
if *fs {
@@ -5333,7 +5378,7 @@ pub fn filter_list_completed_query(
}
if let Some(jk) = &lq.job_kinds {
sqlb.and_where_in(
"job_kind",
"kind",
&jk.split(',').into_iter().map(quote).collect::<Vec<_>>(),
);
}
@@ -5347,7 +5392,8 @@ pub fn filter_list_completed_query(
}
if lq.is_not_schedule.unwrap_or(false) {
sqlb.and_where("schedule_path IS null");
sqlb.and_where("trigger_kind != 'schedule'")
.or_where("trigger_kind IS NULL");
}
sqlb
@@ -5362,9 +5408,9 @@ pub fn list_completed_jobs_query(
join_outstanding_wait_times: bool,
tags: Option<Vec<&str>>,
) -> SqlBuilder {
let mut sqlb = SqlBuilder::select_from("v2_as_completed_job")
let mut sqlb = SqlBuilder::select_from("v2_job_completed")
.fields(fields)
.order_by("created_at", lq.order_desc.unwrap_or(true))
.order_by("v2_job.created_at", lq.order_desc.unwrap_or(true))
.offset(offset)
.limit(per_page)
.clone();
@@ -5427,35 +5473,35 @@ async fn list_completed_jobs(
offset,
&lq,
&[
"id",
"workspace_id",
"parent_job",
"created_by",
"created_at",
"started_at",
"duration_ms",
"success",
"script_hash",
"script_path",
"deleted",
"canceled",
"canceled_by",
"canceled_reason",
"job_kind",
"schedule_path",
"permissioned_as",
"v2_job.id",
"v2_job.workspace_id",
"v2_job.parent_job",
"v2_job.created_by",
"v2_job.created_at",
"v2_job_completed.started_at",
"v2_job_completed.duration_ms",
"v2_job_completed.status = 'success' OR v2_job_completed.status = 'skipped' as success",
"v2_job.runnable_id as script_hash",
"v2_job.runnable_path as script_path",
"false as deleted",
"v2_job_completed.status = 'canceled' as canceled",
"v2_job_completed.canceled_by",
"v2_job_completed.canceled_reason",
"v2_job.kind as job_kind",
"CASE WHEN v2_job.trigger_kind = 'schedule' THEN v2_job.trigger END as schedule_path",
"v2_job.permissioned_as",
"null as raw_code",
"null as flow_status",
"null as raw_flow",
"is_flow_step",
"language",
"is_skipped",
"email",
"visible_to_owner",
"mem_peak",
"tag",
"priority",
"result->'wm_labels' as labels",
"v2_job.flow_step_id IS NOT NULL as is_flow_step",
"v2_job.script_lang as language",
"v2_job_completed.status = 'skipped' as is_skipped",
"v2_job.permissioned_as_email as email",
"v2_job.visible_to_owner",
"v2_job_completed.memory_peak as mem_peak",
"v2_job.tag",
"v2_job.priority",
"v2_job_completed.result->'wm_labels' as labels",
"'CompletedJob' as type",
],
false,

View File

@@ -106,7 +106,6 @@ mod slack_approvals;
mod smtp_server_ee;
mod static_assets;
mod stripe_ee;
#[cfg(feature = "enterprise")]
mod teams_ee;
mod tracing_init;
mod triggers;

View File

@@ -329,16 +329,30 @@ pub struct ListScheduleQuery {
pub path_start: Option<String>,
}
#[derive(sqlx::FromRow, Serialize, Deserialize, Debug, Clone)]
pub struct ScheduleLight {
pub workspace_id: String,
pub path: String,
pub edited_by: String,
pub edited_at: DateTime<chrono::Utc>,
pub schedule: String,
pub timezone: String,
pub enabled: bool,
pub script_path: String,
pub is_flow: bool,
pub summary: Option<String>,
pub extra_perms: serde_json::Value,
}
async fn list_schedule(
authed: ApiAuthed,
Extension(user_db): Extension<UserDB>,
Path(w_id): Path<String>,
Query(lsq): Query<ListScheduleQuery>,
) -> JsonResult<Vec<Schedule>> {
) -> JsonResult<Vec<ScheduleLight>> {
let mut tx = user_db.begin(&authed).await?;
let (per_page, offset) = paginate(Pagination { per_page: lsq.per_page, page: lsq.page });
let mut sqlb = SqlBuilder::select_from("schedule")
.field("*")
.field("workspace_id, path, edited_by, edited_at, schedule, timezone, enabled, script_path, is_flow, summary, extra_perms")
.order_by("edited_at", true)
.and_where("workspace_id = ?".bind(&w_id))
.offset(offset)
@@ -357,7 +371,7 @@ async fn list_schedule(
sqlb.and_where_like_left("path", path_start);
}
let sql = sqlb.sql().map_err(|e| Error::internal_err(e.to_string()))?;
let rows = sqlx::query_as::<_, Schedule>(&sql)
let rows = sqlx::query_as::<_, ScheduleLight>(&sql)
.fetch_all(&mut *tx)
.await?;
tx.commit().await?;
@@ -366,36 +380,8 @@ async fn list_schedule(
#[derive(Serialize, Deserialize, Debug)]
pub struct ScheduleWJobs {
pub workspace_id: String,
pub path: String,
pub edited_by: String,
pub edited_at: DateTime<chrono::Utc>,
pub schedule: String,
pub timezone: String,
pub enabled: bool,
pub script_path: String,
pub is_flow: bool,
pub args: Option<serde_json::Value>,
pub extra_perms: serde_json::Value,
pub email: String,
pub error: Option<String>,
pub on_failure: Option<String>,
pub on_failure_times: Option<i32>,
pub on_failure_exact: Option<bool>,
pub on_failure_extra_args: Option<serde_json::Value>,
pub on_recovery: Option<String>,
pub on_recovery_times: Option<i32>,
pub on_recovery_extra_args: Option<serde_json::Value>,
pub on_success: Option<String>,
pub on_success_extra_args: Option<serde_json::Value>,
pub ws_error_handler_muted: bool,
pub retry: Option<serde_json::Value>,
pub jobs: Option<Vec<serde_json::Value>>,
pub summary: Option<String>,
pub no_flow_overlap: bool,
pub tag: Option<String>,
pub paused_until: Option<DateTime<Utc>>,
pub cron_version: Option<String>,
}
async fn list_schedule_with_jobs(
@@ -407,9 +393,27 @@ async fn list_schedule_with_jobs(
let mut tx = user_db.begin(&authed).await?;
let (per_page, offset) = paginate(pagination);
let rows = sqlx::query_as!(ScheduleWJobs,
"SELECT schedule.*, t.jobs FROM schedule, LATERAL ( SELECT ARRAY (SELECT json_build_object('id', id, 'success', success, 'duration_ms', duration_ms) FROM v2_as_completed_job WHERE
v2_as_completed_job.schedule_path = schedule.path AND v2_as_completed_job.workspace_id = $1 AND parent_job IS NULL AND is_skipped = False ORDER BY started_at DESC LIMIT 20) AS jobs ) t
WHERE schedule.workspace_id = $1 ORDER BY schedule.edited_at desc LIMIT $2 OFFSET $3",
// Query plan:
// - use of the `ix_completed_job_workspace_id_started_at_new_2` index first, then;
// - use of the `ix_v2_job_root_by_path` index; hence the `parent_job IS NULL` clause.
// - both `workspace_id = $1` checks are required to hit both indexes.
"SELECT
schedule.path, t.jobs FROM schedule,
LATERAL(SELECT ARRAY(
SELECT json_build_object('id', id, 'success', status = 'success', 'duration_ms', duration_ms)
FROM v2_job_completed c JOIN v2_job j USING (id)
WHERE trigger_kind = 'schedule'
AND trigger = schedule.path
AND c.workspace_id = $1
AND j.workspace_id = $1
AND parent_job IS NULL AND runnable_path = schedule.script_path
AND status <> 'skipped'
ORDER BY created_at DESC
LIMIT 20
) AS jobs) t
WHERE workspace_id = $1
ORDER BY edited_at DESC
LIMIT $2 OFFSET $3",
w_id,
per_page as i64,
offset as i64

View File

@@ -625,6 +625,19 @@ async fn create_script_internal<'c>(
} else {
ns.language.clone()
};
let (no_main_func, has_preprocessor) = match lang {
ScriptLang::Bun | ScriptLang::Bunnative | ScriptLang::Deno | ScriptLang::Nativets => {
let args = windmill_parser_ts::parse_deno_signature(&ns.content, true, true, None)?;
(args.no_main_func, args.has_preprocessor)
}
ScriptLang::Python3 => {
let args = windmill_parser_py::parse_python_signature(&ns.content, None, true)?;
(args.no_main_func, args.has_preprocessor)
}
_ => (ns.no_main_func, ns.has_preprocessor),
};
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, \
@@ -660,9 +673,9 @@ async fn create_script_internal<'c>(
ns.timeout,
ns.concurrency_key,
ns.visible_to_runner_only,
ns.no_main_func,
no_main_func.filter(|x| *x), // should be Some(true) or None
codebase,
ns.has_preprocessor,
has_preprocessor.filter(|x| *x), // should be Some(true) or None
if ns.on_behalf_of_email.is_some() {
Some(&authed.email)
} else {

View File

@@ -1,5 +1,39 @@
use http::status::StatusCode;
#[cfg(feature = "enterprise")]
use axum::Router;
use windmill_common::error::Error;
pub async fn edit_teams_command() -> Result<StatusCode, Error> {
return Err(Error::BadRequest(
"Teams only available on enterprise".to_string(),
));
}
pub async fn workspaces_list_available_teams_ids() -> Result<StatusCode, Error> {
return Err(Error::BadRequest(
"Teams only available on enterprise".to_string(),
));
}
pub async fn connect_teams() -> Result<StatusCode, Error> {
return Err(Error::BadRequest(
"Teams only available on enterprise".to_string(),
));
}
pub async fn run_teams_message_test_job() -> Result<StatusCode, Error> {
return Err(Error::BadRequest(
"Teams only available on enterprise".to_string(),
));
}
pub async fn workspaces_list_available_teams_channels() -> Result<StatusCode, Error> {
return Err(Error::BadRequest(
"Teams only available on enterprise".to_string(),
));
}
#[cfg(feature = "enterprise")]
pub fn teams_service() -> Router {
Router::new()
}

View File

@@ -58,6 +58,11 @@ use sqlx::{FromRow, Postgres, Transaction};
use windmill_common::oauth2::InstanceEvent;
use windmill_common::utils::not_found_if_none;
use crate::teams_ee::{
connect_teams, edit_teams_command, run_teams_message_test_job,
workspaces_list_available_teams_channels, workspaces_list_available_teams_ids,
};
lazy_static::lazy_static! {
static ref WORKSPACE_KEY_REGEXP: Regex = Regex::new("^[a-zA-Z0-9]{64}$").unwrap();
}
@@ -73,10 +78,24 @@ pub fn workspaced_service() -> Router {
.route("/get_settings", get(get_settings))
.route("/get_deploy_to", get(get_deploy_to))
.route("/edit_slack_command", post(edit_slack_command))
.route("/edit_teams_command", post(edit_teams_command))
.route(
"/available_teams_ids",
get(workspaces_list_available_teams_ids),
)
.route(
"/available_teams_channels",
get(workspaces_list_available_teams_channels),
)
.route("/connect_teams", post(connect_teams))
.route(
"/run_slack_message_test_job",
post(run_slack_message_test_job),
)
.route(
"/run_teams_message_test_job",
post(run_teams_message_test_job),
)
.route("/edit_webhook", post(edit_webhook))
.route("/edit_auto_invite", post(edit_auto_invite))
.route("/edit_deploy_to", post(edit_deploy_to))
@@ -168,9 +187,14 @@ pub struct WorkspaceSettings {
#[serde(skip_serializing_if = "Option::is_none")]
pub slack_team_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub teams_team_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub teams_team_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub slack_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub slack_command_script: Option<String>,
pub teams_command_script: Option<String>,
pub slack_email: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub auto_invite_domain: Option<String>,
@@ -188,7 +212,7 @@ pub struct WorkspaceSettings {
pub deploy_to: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ai_resource: Option<serde_json::Value>,
pub ai_models: Vec<String>,
pub ai_models: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub code_completion_model: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
@@ -429,7 +453,7 @@ async fn get_settings(
let mut tx = user_db.begin(&authed).await?;
let settings = sqlx::query_as!(
WorkspaceSettings,
"SELECT * FROM workspace_settings WHERE workspace_id = $1",
"SELECT workspace_id, slack_team_id, teams_team_id, teams_team_name, slack_name, slack_command_script, teams_command_script, slack_email, auto_invite_domain, auto_invite_operator, auto_add, customer_id, plan, webhook, deploy_to, ai_resource, ai_models, code_completion_model, error_handler, error_handler_extra_args, error_handler_muted_on_cancel, large_file_storage, git_sync, deploy_ui, default_app, automatic_billing, default_scripts, mute_critical_alerts, color, operator_settings FROM workspace_settings WHERE workspace_id = $1",
&w_id
)
.fetch_one(&mut *tx)
@@ -1380,9 +1404,15 @@ async fn list_workspaces_as_super_admin(
let mut tx = user_db.begin(&authed).await?;
let workspaces = sqlx::query_as!(
Workspace,
"SELECT workspace.id, workspace.name, workspace.owner, workspace.deleted, workspace.premium, workspace_settings.color
FROM workspace
LEFT JOIN workspace_settings ON workspace.id = workspace_settings.workspace_id
"SELECT
workspace.id AS \"id!\",
workspace.name AS \"name!\",
workspace.owner AS \"owner!\",
workspace.deleted AS \"deleted!\",
workspace.premium AS \"premium!\",
workspace_settings.color AS \"color\"
FROM workspace
LEFT JOIN workspace_settings ON workspace.id = workspace_settings.workspace_id
LIMIT $1 OFFSET $2",
per_page as i32,
offset as i32

View File

@@ -47,8 +47,11 @@ lazy_static::lazy_static! {
.connect_timeout(std::time::Duration::from_secs(10))
.build().unwrap();
pub static ref GIT_SEM_VERSION: Version = Version::parse(
// skip first `v` character.
GIT_VERSION.split_at(1).1
if GIT_VERSION.starts_with('v') {
&GIT_VERSION[1..]
} else {
GIT_VERSION
}
).unwrap_or(Version::new(0, 1, 0));
}

View File

@@ -95,6 +95,7 @@ lazy_static::lazy_static! {
.unwrap_or(false);
pub static ref MIN_VERSION: Arc<RwLock<Version>> = Arc::new(RwLock::new(Version::new(0, 0, 0)));
pub static ref MIN_VERSION_IS_AT_LEAST_1_461: Arc<RwLock<bool>> = Arc::new(RwLock::new(false));
pub static ref MIN_VERSION_IS_AT_LEAST_1_427: Arc<RwLock<bool>> = Arc::new(RwLock::new(false));
pub static ref MIN_VERSION_IS_AT_LEAST_1_432: Arc<RwLock<bool>> = Arc::new(RwLock::new(false));
pub static ref MIN_VERSION_IS_AT_LEAST_1_440: Arc<RwLock<bool>> = Arc::new(RwLock::new(false));
@@ -103,6 +104,8 @@ lazy_static::lazy_static! {
pub static ref DISABLE_FLOW_SCRIPT: bool = std::env::var("DISABLE_FLOW_SCRIPT").ok().is_some_and(|x| x == "1" || x == "true");
}
pub static MIN_VERSION_IS_LATEST: AtomicBool = AtomicBool::new(false);
fn format_pull_query(peek: String) -> String {
let r = format!(
"WITH peek AS (
@@ -654,7 +657,7 @@ pub async fn update_min_version<'c, E: sqlx::Executor<'c, Database = sqlx::Postg
let min_version = pings
.iter()
.filter(|x| !x.is_empty())
.filter_map(|x| semver::Version::parse(x.split_at(1).1).ok())
.filter_map(|x| semver::Version::parse(if x.starts_with('v') { &x[1..] } else { x }).ok())
.min()
.unwrap_or_else(|| cur_version.clone());
@@ -662,6 +665,7 @@ pub async fn update_min_version<'c, E: sqlx::Executor<'c, Database = sqlx::Postg
tracing::info!("Minimal worker version: {min_version}");
}
*MIN_VERSION_IS_AT_LEAST_1_461.write().await = min_version >= Version::new(1, 461, 0);
*MIN_VERSION_IS_AT_LEAST_1_427.write().await = min_version >= Version::new(1, 427, 0);
*MIN_VERSION_IS_AT_LEAST_1_432.write().await = min_version >= Version::new(1, 432, 0);
*MIN_VERSION_IS_AT_LEAST_1_440.write().await = min_version >= Version::new(1, 440, 0);

View File

@@ -566,6 +566,9 @@ pub async fn add_completed_job<T: Serialize + Send + Sync + ValidableJson>(
let result_columns = result_columns.as_ref();
let _job_id = queued_job.id;
let (opt_uuid, _duration, _skip_downstream_error_handlers) = (|| async {
// let start = std::time::Instant::now();
let mut tx = db.begin().await?;
let job_id = queued_job.id;
@@ -663,7 +666,7 @@ pub async fn add_completed_job<T: Serialize + Send + Sync + ValidableJson>(
// tracing::error!("Added completed job {:#?}", queued_job);
let mut _skip_downstream_error_handlers = false;
tx = delete_job(tx, &queued_job.workspace_id, job_id).await?;
tx = delete_job(tx, &job_id).await?;
// tracing::error!("3 {:?}", start.elapsed());
if queued_job.is_flow_step {
@@ -858,6 +861,7 @@ pub async fn add_completed_job<T: Serialize + Send + Sync + ValidableJson>(
"inserted completed job: {} (success: {success})",
queued_job.id
);
// tracing::info!("completed job: {:?}", start.elapsed().as_micros());
Ok((None, _duration, _skip_downstream_error_handlers)) as windmill_common::error::Result<(Option<Uuid>, i64, bool)>
})
.retry(
@@ -1377,12 +1381,17 @@ async fn apply_schedule_handlers<'a, 'c, T: Serialize + Send + Sync>(
let exact = schedule.on_failure_exact.unwrap_or(false);
if times > 1 || exact {
let past_jobs = sqlx::query!(
"SELECT
success AS \"success!\",
result AS \"result: Json<Box<RawValue>>\",
started_at AS \"started_at!\"
FROM v2_as_completed_job
WHERE workspace_id = $1 AND schedule_path = $2 AND script_path = $3 AND id != $4
// Query plan:
// - use of the `ix_v2_job_root_by_path` index;
// hence the `parent_job IS NULL` clause.
// - select from `v2_job` first, then join with `v2_job_completed` to avoid a full
// table scan.
"SELECT status = 'success' AS \"success!\"
FROM v2_job j JOIN v2_job_completed USING (id)
WHERE j.workspace_id = $1 AND trigger_kind = 'schedule' AND trigger = $2
AND parent_job IS NULL
AND runnable_path = $3
AND j.id != $4
ORDER BY created_at DESC
LIMIT $5",
&schedule.workspace_id,
@@ -1448,11 +1457,19 @@ async fn apply_schedule_handlers<'a, 'c, T: Serialize + Send + Sync>(
let tx = db.begin().await?;
let times = schedule.on_recovery_times.unwrap_or(1).max(1);
let past_jobs = sqlx::query!(
"SELECT
success AS \"success!\",
// Query plan:
// - use of the `ix_v2_job_root_by_path` index;
// hence the `parent_job IS NULL` clause.
// - select from `v2_job` first, then join with `v2_job_completed` to avoid a full
// table scan.
"SELECT status = 'success' AS \"success!\",
result AS \"result: Json<Box<RawValue>>\",
started_at AS \"started_at!\"\
FROM v2_as_completed_job WHERE workspace_id = $1 AND schedule_path = $2 AND script_path = $3 AND id != $4
FROM v2_job j JOIN v2_job_completed USING (id)
WHERE j.workspace_id = $1 AND trigger_kind = 'schedule' AND trigger = $2
AND parent_job IS NULL
AND runnable_path = $3
AND j.id != $4
ORDER BY created_at DESC
LIMIT $5",
&schedule.workspace_id,
@@ -2095,12 +2112,15 @@ async fn pull_single_job_and_mark_as_running_no_concurrency_limit<'c>(
for query in queries.iter() {
// tracing::info!("Pulling job with query: {}", query);
// let instant = std::time::Instant::now();
let r = sqlx::query_as::<_, PulledJob>(query)
.bind(worker_name)
.fetch_optional(db)
.await?;
if let Some(pulled_job) = r {
// tracing::info!("pulled job: {:?}", instant.elapsed().as_micros());
highest_priority_job = Some(pulled_job);
break;
}
@@ -2581,21 +2601,17 @@ async fn extract_result_from_job_result(
pub async fn delete_job<'c>(
mut tx: Transaction<'c, Postgres>,
w_id: &str,
job_id: Uuid,
job_id: &Uuid,
) -> windmill_common::error::Result<Transaction<'c, Postgres>> {
#[cfg(feature = "prometheus")]
if METRICS_ENABLED.load(std::sync::atomic::Ordering::Relaxed) {
QUEUE_DELETE_COUNT.inc();
}
let job_removed = sqlx::query_scalar!(
"DELETE FROM v2_job_queue WHERE workspace_id = $1 AND id = $2 RETURNING 1",
w_id,
job_id
)
.fetch_optional(&mut *tx)
.await;
let job_removed =
sqlx::query_scalar!("DELETE FROM v2_job_queue WHERE id = $1 RETURNING 1", job_id,)
.fetch_optional(&mut *tx)
.await;
if let Err(job_removed) = job_removed {
tracing::error!(

View File

@@ -9,7 +9,7 @@
use crate::push;
use crate::PushIsolationLevel;
use anyhow::Context;
use sqlx::{query_scalar, PgExecutor, Postgres, Transaction};
use sqlx::{PgExecutor, Postgres, Transaction};
use std::collections::HashMap;
use std::str::FromStr;
use windmill_common::db::Authed;
@@ -70,11 +70,21 @@ pub async fn push_scheduled_job<'c>(
// Scheduled events must be stored in the database in UTC
let next = next.with_timezone(&chrono::Utc);
let already_exists: bool = query_scalar!(
"SELECT EXISTS (SELECT 1 FROM v2_as_queue WHERE workspace_id = $1 AND schedule_path = $2 AND scheduled_for = $3)",
let already_exists: bool = sqlx::query_scalar!(
// Query plan:
// - use of the `ix_v2_job_root_by_path` index; hence the `parent_job IS NULL` clause.
// - select from `v2_job` first, then join with `v2_job_queue` to avoid a full table scan
// on `scheduled_for = $3`.
"SELECT EXISTS (
SELECT 1 FROM v2_job j JOIN v2_job_queue USING (id)
WHERE j.workspace_id = $1 AND trigger_kind = 'schedule' AND trigger = $2 AND runnable_path = $4
AND parent_job IS NULL
AND scheduled_for = $3
)",
&schedule.workspace_id,
&schedule.path,
next
next,
&schedule.script_path
)
.fetch_one(&mut *tx)
.await?

View File

@@ -1,14 +1,12 @@
#[cfg(feature = "deno_core")]
use std::time::Instant;
use std::{collections::HashMap, fs, path::Path, process::Stdio};
use std::{collections::HashMap, fs, process::Stdio};
use anyhow::Context;
use base64::Engine;
use itertools::Itertools;
use serde_json::value::RawValue;
use sha2::Digest;
use uuid::Uuid;
use windmill_parser_ts::remove_pinned_imports;
use windmill_queue::{append_logs, CanceledBy};
@@ -23,8 +21,8 @@ use crate::{
},
handle_child::handle_child,
AuthedClientBackgroundTask, BUNFIG_INSTALL_SCOPES, BUN_BUNDLE_CACHE_DIR, BUN_CACHE_DIR,
BUN_DEPSTAR_CACHE_DIR, BUN_PATH, DISABLE_NSJAIL, DISABLE_NUSER, HOME_ENV, NODE_BIN_PATH,
NODE_PATH, NPM_CONFIG_REGISTRY, NPM_PATH, NSJAIL_PATH, PATH_ENV, PROXY_ENVS, TZ_ENV,
BUN_PATH, DISABLE_NSJAIL, DISABLE_NUSER, HOME_ENV, NODE_BIN_PATH, NODE_PATH,
NPM_CONFIG_REGISTRY, NPM_PATH, NSJAIL_PATH, PATH_ENV, PROXY_ENVS, TZ_ENV,
};
#[cfg(windows)]
@@ -637,51 +635,6 @@ pub async fn pull_codebase(_w_id: &str, _id: &str, _job_dir: &str) -> Result<()>
));
}
#[cfg(unix)]
pub fn copy_recursively(
source: impl AsRef<Path>,
destination: impl AsRef<Path>,
skip: Option<&Vec<String>>,
) -> Result<()> {
let mut stack = Vec::new();
stack.push((
source.as_ref().to_path_buf(),
destination.as_ref().to_path_buf(),
0,
));
while let Some((current_source, current_destination, level)) = stack.pop() {
for entry in fs::read_dir(&current_source)
.context(format!("reading directory {current_source:?}"))?
{
let entry = entry?;
let filetype = entry.file_type()?;
let destination = current_destination.join(entry.file_name());
if level == 0 {
if let Some(skip) = skip {
if skip.contains(&entry.file_name().to_string_lossy().to_string()) {
continue;
}
}
}
let original = entry.path();
if filetype.is_dir() {
fs::create_dir_all(&destination)?;
stack.push((entry.path(), destination, level + 1));
} else {
fs::hard_link(&original, &destination).map_err(|e| {
error::Error::internal_err(format!(
"hard linking from {original:?} to {destination:?}: {e:#}"
))
})?;
}
}
}
Ok(())
}
pub async fn prebundle_bun_script(
inner_content: &str,
lockfile: Option<&String>,
@@ -889,7 +842,6 @@ pub async fn handle_bun_job(
));
}
let mut gbuntar_name: Option<String> = None;
if has_bundle_cache {
let target;
let symlink;
@@ -924,67 +876,23 @@ pub async fn handle_bun_job(
let _ = write_file(job_dir, "package.json", pkg)?;
let lock = if annotation.npm { "" } else { lock.unwrap() };
if !empty {
let mut skip_install = false;
let mut create_buntar = false;
let mut buntar_path = "".to_string();
if !annotation.npm {
let _ = write_lock(lock, job_dir, is_binary).await?;
let mut sha_path = sha2::Sha256::new();
sha_path.update(lock.as_bytes());
let buntar_name =
base64::engine::general_purpose::URL_SAFE.encode(sha_path.finalize());
buntar_path = format!("{BUN_DEPSTAR_CACHE_DIR}/{buntar_name}");
#[cfg(unix)]
if tokio::fs::metadata(&buntar_path).await.is_ok() {
if let Err(e) = copy_recursively(&buntar_path, job_dir, None) {
tracing::error!("Could not extract buntar: {e:#}");
} else {
gbuntar_name = Some(buntar_name.clone());
skip_install = true;
}
} else {
create_buntar = true;
}
}
if !skip_install {
install_bun_lockfile(
mem_peak,
canceled_by,
&job.id,
&job.workspace_id,
Some(db),
job_dir,
worker_name,
common_bun_proc_envs.clone(),
annotation.npm,
&mut Some(occupancy_metrics),
)
.await?;
#[cfg(unix)]
if create_buntar {
fs::create_dir_all(&buntar_path)?;
if let Err(e) = copy_recursively(
job_dir,
&buntar_path,
Some(&vec![
"main.ts".to_string(),
"package.json".to_string(),
if is_binary { "bun.lockb" } else { "bun.lock" }.to_string(),
"shared".to_string(),
"bunfig.toml".to_string(),
]),
) {
fs::remove_dir_all(&buntar_path).context("deleting buntar directory")?;
tracing::error!("Could not create buntar: {e}");
}
}
}
install_bun_lockfile(
mem_peak,
canceled_by,
&job.id,
&job.workspace_id,
Some(db),
job_dir,
worker_name,
common_bun_proc_envs.clone(),
annotation.npm,
&mut Some(occupancy_metrics),
)
.await?;
}
} else {
// if !*DISABLE_NSJAIL || !empty_trusted_deps || has_custom_config_registry {
@@ -1031,13 +939,6 @@ pub async fn handle_bun_job(
"\n\n--- BUN CODE EXECUTION ---\n".to_string()
};
if let Some(gbuntar_name) = gbuntar_name {
init_logs = format!(
"\nskipping install, using cached buntar based on lockfile hash: {gbuntar_name}{}",
init_logs
);
}
if has_bundle_cache {
init_logs = format!("\n{}{}", cache_logs, init_logs);
}
@@ -1050,6 +951,7 @@ pub async fn handle_bun_job(
let args = windmill_parser_ts::parse_deno_signature(
inner_content,
true,
false,
main_override.map(ToString::to_string),
)?
.args;
@@ -1059,6 +961,7 @@ pub async fn handle_bun_job(
windmill_parser_ts::parse_deno_signature(
inner_content,
true,
false,
Some("preprocessor".to_string()),
)?
.args,
@@ -1672,7 +1575,7 @@ pub async fn start_worker(
{
// let mut start = Instant::now();
let args = windmill_parser_ts::parse_deno_signature(inner_content, true, None)?.args;
let args = windmill_parser_ts::parse_deno_signature(inner_content, true, false, None)?.args;
let dates = args
.iter()
.filter_map(|x| {

View File

@@ -213,6 +213,25 @@ pub fn parse_npm_config(s: &str) -> (String, Option<String>) {
return (url, token_opt);
}
#[async_recursion]
pub async fn get_root_job_id(job: &Uuid, db: &Pool<Postgres>) -> anyhow::Result<Uuid> {
let njob = sqlx::query_scalar!(
"SELECT flow_innermost_root_job FROM v2_job WHERE id = $1",
job
)
.fetch_optional(db)
.await?
.flatten();
if let Some(root_job) = njob {
if root_job == *job {
return Ok(job.to_owned());
}
get_root_job_id(&root_job, db).await
} else {
Ok(job.to_owned())
}
}
#[async_recursion]
pub async fn transform_json_value(
name: &str,
@@ -252,8 +271,10 @@ pub async fn transform_json_value(
}
Value::String(y) if y.starts_with("$encrypted:") => {
let encrypted = y.strip_prefix("$encrypted:").unwrap();
let mc =
build_crypt_with_key_suffix(&db, &job.workspace_id, &job.id.to_string()).await?;
let root_job_id = get_root_job_id(&job.root_job.unwrap_or_else(|| job.id), db).await?;
let mc = build_crypt_with_key_suffix(&db, &job.workspace_id, &root_job_id.to_string())
.await?;
decrypt(&mc, encrypted.to_string()).and_then(|x| {
serde_json::from_str(&x).map_err(|e| Error::internal_err(e.to_string()))
})
@@ -333,7 +354,8 @@ pub fn unsafe_raw(json: String) -> Box<RawValue> {
fn check_result_too_big(size: usize) -> error::Result<()> {
if *CLOUD_HOSTED && size > MAX_RESULT_SIZE {
return Err(error::Error::ExecutionErr("Result is too large for the cloud app (limit 2MB).
If using this script as part of the flow, use the shared folder to pass heavy data between steps.".to_owned()));
We highly recommend using object to store and pass heavy data (https://www.windmill.dev/docs/core_concepts/object_storage_in_windmill#read-a-file-from-s3-within-a-script)
Alternatively, if using this script as part of a flow, activate shared folder and use the shared folder to pass heavy data between steps.".to_owned()));
};
Ok(())
}

View File

@@ -205,6 +205,7 @@ pub async fn handle_deno_job(
let args = windmill_parser_ts::parse_deno_signature(
inner_content,
true,
false,
main_override.map(ToString::to_string),
)?
.args;
@@ -214,6 +215,7 @@ pub async fn handle_deno_job(
windmill_parser_ts::parse_deno_signature(
inner_content,
true,
false,
Some("preprocessor".to_string()),
)?
.args,
@@ -533,7 +535,7 @@ pub async fn start_worker(
{
// let mut start = Instant::now();
let args = windmill_parser_ts::parse_deno_signature(inner_content, true, None)?.args;
let args = windmill_parser_ts::parse_deno_signature(inner_content, true, false, None)?.args;
let dates = args
.iter()
.filter_map(|x| {

View File

@@ -775,7 +775,7 @@ pub async fn eval_fetch_timeout(
let (sender, mut receiver) = oneshot::channel::<IsolateHandle>();
let parsed_args = windmill_parser_ts::parse_deno_signature(&ts_expr, true, None)?.args;
let parsed_args = windmill_parser_ts::parse_deno_signature(&ts_expr, true, false, None)?.args;
let spread = parsed_args
.into_iter()
.map(|x| {

View File

@@ -1296,12 +1296,14 @@ async fn prepare_wrapper(
let sig = windmill_parser_py::parse_python_signature(
inner_content,
main_override.map(ToString::to_string),
false,
)?;
let pre_sig = if apply_preprocessor {
Some(windmill_parser_py::parse_python_signature(
inner_content,
Some("preprocessor".to_string()),
false,
)?)
} else {
None
@@ -1661,7 +1663,7 @@ async fn spawn_uv_install(
.replace("{TARGET_DIR}", &venv_p)
.replace("{CLONE_NEWUSER}", &(!*DISABLE_NUSER).to_string()),
)?;
let mut nsjail_cmd = Command::new(NSJAIL_PATH.as_str());
nsjail_cmd
.current_dir(job_dir)

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