Compare commits
114 Commits
ai/public-
...
rf/pythonI
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb2a7c3ba1 | ||
|
|
06d078ebfa | ||
|
|
4373dfbd80 | ||
|
|
d0c7ac9f95 | ||
|
|
6e132e8ee9 | ||
|
|
51ea9473ef | ||
|
|
c92bfe6601 | ||
|
|
d152e8e58f | ||
|
|
28f1d61164 | ||
|
|
54f36fcce7 | ||
|
|
14b0edd8a4 | ||
|
|
958e8af782 | ||
|
|
4b79e53f0d | ||
|
|
58bc913dfc | ||
|
|
511ff5e9f7 | ||
|
|
aa5a0300f4 | ||
|
|
47e49b243d | ||
|
|
05648c7c81 | ||
|
|
bcd05753f4 | ||
|
|
ac066abb98 | ||
|
|
ae49737676 | ||
|
|
26a47ee699 | ||
|
|
1734862718 | ||
|
|
c1770cd769 | ||
|
|
18cc474cc7 | ||
|
|
b698ced881 | ||
|
|
49ed757424 | ||
|
|
4349a2024d | ||
|
|
51568eee02 | ||
|
|
7f11eb98b5 | ||
|
|
dfb32d2949 | ||
|
|
205618af0a | ||
|
|
31892ca11e | ||
|
|
eaf4054bd3 | ||
|
|
5e73c49ab6 | ||
|
|
896238a1a7 | ||
|
|
ccf755b351 | ||
|
|
68bf2955f7 | ||
|
|
03c82af00a | ||
|
|
f4851e7747 | ||
|
|
396b6e5c7f | ||
|
|
11dd4118ce | ||
|
|
9b07d6d546 | ||
|
|
eae0c09979 | ||
|
|
af226162f5 | ||
|
|
c2de0a8e61 | ||
|
|
afc4044bbd | ||
|
|
65bcc00cd9 | ||
|
|
8277920a3f | ||
|
|
1a2ba21a17 | ||
|
|
1661bcf90c | ||
|
|
1005662dfc | ||
|
|
7ead7a2829 | ||
|
|
5f5596a970 | ||
|
|
a5305897c5 | ||
|
|
bc33d62345 | ||
|
|
c800d7b353 | ||
|
|
4bf4531fba | ||
|
|
08bc836ed5 | ||
|
|
eb18d0d1f7 | ||
|
|
f1492036a7 | ||
|
|
4398013e81 | ||
|
|
80d12426f6 | ||
|
|
58975b58dc | ||
|
|
57155dd318 | ||
|
|
24604c35ba | ||
|
|
b82e6516ef | ||
|
|
f250d775ce | ||
|
|
87b76c0cb6 | ||
|
|
4ec1dce531 | ||
|
|
2b37281084 | ||
|
|
76569abb1e | ||
|
|
8fb082e5f3 | ||
|
|
34773f2614 | ||
|
|
a41edd236b | ||
|
|
1892895cd9 | ||
|
|
67381436a5 | ||
|
|
a4be29c34d | ||
|
|
f8ba3d1a1b | ||
|
|
ef14290265 | ||
|
|
36b742b3ad | ||
|
|
3d6d697ed3 | ||
|
|
f03a8d69c0 | ||
|
|
e1629f799d | ||
|
|
735ca2f70f | ||
|
|
8ec4d615d2 | ||
|
|
85a9c91895 | ||
|
|
0dc84254fc | ||
|
|
60dd969d6c | ||
|
|
0893ce103f | ||
|
|
22c90ba090 | ||
|
|
8bcd555351 | ||
|
|
1112de87d4 | ||
|
|
322f68053a | ||
|
|
1fef46027b | ||
|
|
c27df6a917 | ||
|
|
13bf33f83c | ||
|
|
2471c7acad | ||
|
|
49f6a3d979 | ||
|
|
a47463e053 | ||
|
|
e134364afe | ||
|
|
47c6386d0f | ||
|
|
4ebea68d73 | ||
|
|
ea2f71d8be | ||
|
|
2648520b53 | ||
|
|
962465dd8b | ||
|
|
eb5ac2594c | ||
|
|
147e6975c4 | ||
|
|
be6db04397 | ||
|
|
fcc2c080da | ||
|
|
ff08759a1a | ||
|
|
c8fea3d34a | ||
|
|
2a6424672b | ||
|
|
49e6af0302 |
8
.github/workflows/check-org-membership.yml
vendored
8
.github/workflows/check-org-membership.yml
vendored
@@ -46,7 +46,13 @@ jobs:
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 2. Otherwise fall back to the org-membership check
|
||||
# 2. Disallow other bots
|
||||
if [[ "${COMMENTER}" =~ \[bot\]$ ]]; then
|
||||
echo "is_member=false" >> $GITHUB_OUTPUT
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 3. Otherwise check if the user is a member of the organization
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
|
||||
-H "Authorization: token $ORG_ACCESS_TOKEN" \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
|
||||
1
.github/workflows/claude.yml
vendored
1
.github/workflows/claude.yml
vendored
@@ -98,6 +98,7 @@ jobs:
|
||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
timeout_minutes: "60"
|
||||
allowed_tools: "mcp__github__create_pull_request,Bash"
|
||||
allowed_bots: "windmill-internal-app[bot]"
|
||||
custom_instructions: |
|
||||
## IMPORTANT INSTRUCTIONS
|
||||
- Your branch name should be a short description of the requested changes.
|
||||
|
||||
27
.github/workflows/rust-client-check.yml
vendored
Normal file
27
.github/workflows/rust-client-check.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
name: Rust Client Check
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["Change versions"]
|
||||
types:
|
||||
- completed
|
||||
push:
|
||||
paths:
|
||||
- "rust-client/**"
|
||||
- "backend/**/*.rs"
|
||||
- "backend/windmill-api/openapi.yaml"
|
||||
- "version.txt"
|
||||
- "flake.nix"
|
||||
- ".github/workflows/rust-client-check.yml"
|
||||
|
||||
jobs:
|
||||
check_rust_client:
|
||||
runs-on: ubicloud-standard-8
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: cachix/install-nix-action@v20
|
||||
with:
|
||||
extra_nix_config: |
|
||||
experimental-features = nix-command flakes
|
||||
- name: Check rust client builds
|
||||
run: cd rust-client && nix develop ../ --command ./dev.nu --check
|
||||
timeout-minutes: 16
|
||||
163
CHANGELOG.md
163
CHANGELOG.md
@@ -1,5 +1,168 @@
|
||||
# Changelog
|
||||
|
||||
## [1.530.0](https://github.com/windmill-labs/windmill/compare/v1.529.0...v1.530.0) (2025-08-20)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **mcp:** add script preview testing tool ([#6417](https://github.com/windmill-labs/windmill/issues/6417)) ([ae49737](https://github.com/windmill-labs/windmill/commit/ae497376769f5cd49a41c22cf558a9f052d5b56e))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* aggrid newchange to point to correct idx ([#6425](https://github.com/windmill-labs/windmill/issues/6425)) ([511ff5e](https://github.com/windmill-labs/windmill/commit/511ff5e9f794c29c3c8a5fc0480675a1258fb056))
|
||||
* fix preprocessor preview ([47e49b2](https://github.com/windmill-labs/windmill/commit/47e49b243d8cf6d29fa5a59918a2168b87111352))
|
||||
* improve flow editor log streaming for individual tests ([ac066ab](https://github.com/windmill-labs/windmill/commit/ac066abb980501577cc96330a4a5f1309aa35661))
|
||||
|
||||
## [1.529.0](https://github.com/windmill-labs/windmill/compare/v1.528.0...v1.529.0) (2025-08-19)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add prometheus metric queue_running_count ([#6413](https://github.com/windmill-labs/windmill/issues/6413)) ([49ed757](https://github.com/windmill-labs/windmill/commit/49ed7574245784681f800199b6c7a47df5788e45))
|
||||
* **aichat:** add tool to test specific module in flow mode ([#6381](https://github.com/windmill-labs/windmill/issues/6381)) ([dfb32d2](https://github.com/windmill-labs/windmill/commit/dfb32d2949541ed149722cff88918d7c6e3dc307))
|
||||
* **frontend:** add relative line numbers toggle ([#6416](https://github.com/windmill-labs/windmill/issues/6416)) ([4349a20](https://github.com/windmill-labs/windmill/commit/4349a2024da2aa7406b16254fbfc427526718903))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **cli:** pass HEADERS environment variable to fetch calls in generate-locks ([#6422](https://github.com/windmill-labs/windmill/issues/6422)) ([7f11eb9](https://github.com/windmill-labs/windmill/commit/7f11eb98b5682511e05c270d7ba860e3e0db61e9))
|
||||
* improve computeAssetNodes rendering caching and performance ([#6414](https://github.com/windmill-labs/windmill/issues/6414)) ([51568ee](https://github.com/windmill-labs/windmill/commit/51568eee025eab6e0069a8e719a562b721fc8c43))
|
||||
|
||||
## [1.528.0](https://github.com/windmill-labs/windmill/compare/v1.527.1...v1.528.0) (2025-08-19)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* native k8s autoscaling integration (EE) ([#6405](https://github.com/windmill-labs/windmill/issues/6405)) ([eaf4054](https://github.com/windmill-labs/windmill/commit/eaf4054bd380101856c02a0d07430ff3a0180880))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* flow status reactivity improvement ([#6402](https://github.com/windmill-labs/windmill/issues/6402)) ([5e73c49](https://github.com/windmill-labs/windmill/commit/5e73c49ab670be0f55794f5d0cb182de9efd500a))
|
||||
|
||||
## [1.527.1](https://github.com/windmill-labs/windmill/compare/v1.527.0...v1.527.1) (2025-08-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **cli:** module not found ../ruby/../wasm.js ([#6399](https://github.com/windmill-labs/windmill/issues/6399)) ([f4851e7](https://github.com/windmill-labs/windmill/commit/f4851e7747c057ea093d55b122a976a1eeec8d98))
|
||||
* fix inlinecompletion errors ([03c82af](https://github.com/windmill-labs/windmill/commit/03c82af00a113378bb7e00d8018c054856eb2314))
|
||||
|
||||
## [1.527.0](https://github.com/windmill-labs/windmill/compare/v1.526.1...v1.527.0) (2025-08-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add ruby support ([#5939](https://github.com/windmill-labs/windmill/issues/5939)) ([11dd411](https://github.com/windmill-labs/windmill/commit/11dd4118ce43136da900601401ee0d04e60c246b))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* improve flow layout for more complex flow ([eae0c09](https://github.com/windmill-labs/windmill/commit/eae0c099790aedb3fd5ac69b551cafc5efc1bd62))
|
||||
|
||||
## [1.526.1](https://github.com/windmill-labs/windmill/compare/v1.526.0...v1.526.1) (2025-08-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add timeouts to more queries to prevent some rare deadlocks scnarios ([65bcc00](https://github.com/windmill-labs/windmill/commit/65bcc00cd9b289193e27a6f74b053e71f90be698))
|
||||
|
||||
## [1.526.0](https://github.com/windmill-labs/windmill/compare/v1.525.0...v1.526.0) (2025-08-14)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* instance groups workspace ([#6380](https://github.com/windmill-labs/windmill/issues/6380)) ([58975b5](https://github.com/windmill-labs/windmill/commit/58975b58dc7ce665000a46873a145263c5d8a38d))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **aichat:** better placeholders based on mode ([#6378](https://github.com/windmill-labs/windmill/issues/6378)) ([f149203](https://github.com/windmill-labs/windmill/commit/f1492036a7c75dcfda4b1e7e0de8c09c29ad4436))
|
||||
* **aichat:** fix usage with gpt models + adapt test flow tool schema ([#6390](https://github.com/windmill-labs/windmill/issues/6390)) ([a530589](https://github.com/windmill-labs/windmill/commit/a5305897c5559e868f1abac945ef1680439d41e0))
|
||||
* better gcp pubsub error status code ([#6385](https://github.com/windmill-labs/windmill/issues/6385)) ([80d1242](https://github.com/windmill-labs/windmill/commit/80d12426f67284495c0c7446c6b91d33311141b4))
|
||||
* **flowEditor:** add diff mode action buttons to inline script editor ([#6379](https://github.com/windmill-labs/windmill/issues/6379)) ([4398013](https://github.com/windmill-labs/windmill/commit/4398013e8107a3085c3482baa7a982665aa873a1))
|
||||
* improve schemaeditor for nested oneOfs ([4bf4531](https://github.com/windmill-labs/windmill/commit/4bf4531fba65da92ae7acbea22b78187e24d7d75))
|
||||
|
||||
## [1.525.0](https://github.com/windmill-labs/windmill/compare/v1.524.0...v1.525.0) (2025-08-14)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **aichat:** add test tool to script and flow mode ([#6367](https://github.com/windmill-labs/windmill/issues/6367)) ([34773f2](https://github.com/windmill-labs/windmill/commit/34773f2614450d0e82b190c04bb446dec74f84dc))
|
||||
* **cli:** add better error handling with path logging for JSON parsing failures ([#6370](https://github.com/windmill-labs/windmill/issues/6370)) ([f03a8d6](https://github.com/windmill-labs/windmill/commit/f03a8d69c017e5ac8bb34cabdfd5c634dc126f3f))
|
||||
* **frontend:** add flow log view ([#6330](https://github.com/windmill-labs/windmill/issues/6330)) ([4ec1dce](https://github.com/windmill-labs/windmill/commit/4ec1dce5313177079177b9d90558e8085599d19d))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* fix csharp build hanging ([ef14290](https://github.com/windmill-labs/windmill/commit/ef14290265eaf327d3e42b7f2fbb9dfd9eb3a873))
|
||||
* fix resource type search when adding resources ([e1629f7](https://github.com/windmill-labs/windmill/commit/e1629f799d60b4ca5db1e469cac57cc6cfc7d83f))
|
||||
* **frontend:** do not open popup when clicking on wand in flow inline script editor ([#6374](https://github.com/windmill-labs/windmill/issues/6374)) ([2b37281](https://github.com/windmill-labs/windmill/commit/2b372810844cd28019145c1a825dd0ac6e924292))
|
||||
* **frontend:** fix minor issues in the UI ([#6382](https://github.com/windmill-labs/windmill/issues/6382)) ([a41edd2](https://github.com/windmill-labs/windmill/commit/a41edd236bdd3196468cdf2586c95ff0a4c1abf5))
|
||||
|
||||
## [1.524.0](https://github.com/windmill-labs/windmill/compare/v1.523.0...v1.524.0) (2025-08-12)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **mcp:** allow filtering by folder ([#6366](https://github.com/windmill-labs/windmill/issues/6366)) ([8ec4d61](https://github.com/windmill-labs/windmill/commit/8ec4d615d251a0a2ed26f3b1907d6f813d91f43c))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **app:** improve copy paste of tables with sub-components ([0dc8425](https://github.com/windmill-labs/windmill/commit/0dc84254fc152df82ffbd137f80ed01225c00043))
|
||||
* fix preprocessor usage in python ([85a9c91](https://github.com/windmill-labs/windmill/commit/85a9c91895d0460e5e7d2d9ff0e53d05e2354386))
|
||||
* fix v1.523.0 rust sdk build ([#6363](https://github.com/windmill-labs/windmill/issues/6363)) ([0893ce1](https://github.com/windmill-labs/windmill/commit/0893ce103ffcfbcb037c9e2ab851e480b61b3735))
|
||||
|
||||
## [1.523.0](https://github.com/windmill-labs/windmill/compare/v1.522.1...v1.523.0) (2025-08-11)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **aichat:** add api mode to call api endpoints ([#6343](https://github.com/windmill-labs/windmill/issues/6343)) ([2471c7a](https://github.com/windmill-labs/windmill/commit/2471c7acad3404dd37649ed661ab8793607b5a97))
|
||||
* **aichat:** add gpt5 compatibility ([#6358](https://github.com/windmill-labs/windmill/issues/6358)) ([49f6a3d](https://github.com/windmill-labs/windmill/commit/49f6a3d979ab8933de197dc0065c2720131fd597))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add extra query params for token request for client credentials ([#6360](https://github.com/windmill-labs/windmill/issues/6360)) ([1112de8](https://github.com/windmill-labs/windmill/commit/1112de87d440db5c8d0ddab6e3812dc432a58705))
|
||||
* **app:** improve carousel list recursive error ([a47463e](https://github.com/windmill-labs/windmill/commit/a47463e05398e4ebe0f2d09ee2eba462bcef217b))
|
||||
* improve app component loading speed ([13bf33f](https://github.com/windmill-labs/windmill/commit/13bf33f83c6660e05b78a8c941c2adc1b486f810))
|
||||
* improve app decision tree behavior ([322f680](https://github.com/windmill-labs/windmill/commit/322f68053a238d6ef7c0116ccfb1a49a19e08f76))
|
||||
* remove spurrious error log for apps ([c27df6a](https://github.com/windmill-labs/windmill/commit/c27df6a917d8a585593de0183f7ff1c5bb2a0321))
|
||||
|
||||
## [1.522.1](https://github.com/windmill-labs/windmill/compare/v1.522.0...v1.522.1) (2025-08-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **app:** handle inline script of components with underscore in apps ([2648520](https://github.com/windmill-labs/windmill/commit/2648520b53925616b02ecab060e4d2d6db8c2e34))
|
||||
* **app:** improve id handling for transformers ([47c6386](https://github.com/windmill-labs/windmill/commit/47c6386d0ff6d59367ee38e0704d0e98802e1bff))
|
||||
* improve validate ID for id editors ([ea2f71d](https://github.com/windmill-labs/windmill/commit/ea2f71d8be424fe13772ec1b7eba85d55bc4eae4))
|
||||
|
||||
## [1.522.0](https://github.com/windmill-labs/windmill/compare/v1.521.0...v1.522.0) (2025-08-08)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add configurable stale jobs detection and cancellation ([147e697](https://github.com/windmill-labs/windmill/commit/147e6975c4b1e6c63e7b6b77c6645f8c88f0f78b))
|
||||
|
||||
## [1.521.0](https://github.com/windmill-labs/windmill/compare/v1.520.1...v1.521.0) (2025-08-08)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add instance-wide workspace prefix option for custom app ([#6180](https://github.com/windmill-labs/windmill/issues/6180)) ([414f099](https://github.com/windmill-labs/windmill/commit/414f09918856eb1d577eb7776273b6697d11e848))
|
||||
* nextcloud oauth ([#6341](https://github.com/windmill-labs/windmill/issues/6341)) ([755e334](https://github.com/windmill-labs/windmill/commit/755e3343035402b5993a516e58d03c10c47c3a00))
|
||||
* togglable manual acknowledgement for gcp trigger ([#6321](https://github.com/windmill-labs/windmill/issues/6321)) ([852bf06](https://github.com/windmill-labs/windmill/commit/852bf064dc4f640dab4248082afade6eae8bb2cc))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* display if tag has an active workers attached to it in tag select ([2a64246](https://github.com/windmill-labs/windmill/commit/2a6424672b5ed6adb1a408ddc8acbf7d7b2221ac))
|
||||
* do not save license key when renewing if the expiry date is earlier than that of the current key ([#6346](https://github.com/windmill-labs/windmill/issues/6346)) ([5a97258](https://github.com/windmill-labs/windmill/commit/5a97258375d76164ed17f7b258fa9b3222459fe1))
|
||||
|
||||
## [1.520.1](https://github.com/windmill-labs/windmill/compare/v1.520.0...v1.520.1) (2025-08-07)
|
||||
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ ARG POWERSHELL_VERSION=7.5.0
|
||||
ARG POWERSHELL_DEB_VERSION=7.5.0-1
|
||||
ARG KUBECTL_VERSION=1.28.7
|
||||
ARG HELM_VERSION=3.14.3
|
||||
ARG GO_VERSION=1.22.5
|
||||
ARG GO_VERSION=1.25.0
|
||||
ARG APP=/usr/src/app
|
||||
ARG WITH_POWERSHELL=true
|
||||
ARG WITH_KUBECTL=true
|
||||
|
||||
3
backend/.gitignore
vendored
3
backend/.gitignore
vendored
@@ -8,4 +8,5 @@ index/
|
||||
windmill-api/openapi-*.*
|
||||
.duckdb/*
|
||||
*ee.rs
|
||||
generate_mcp_endpoints_tools/venv
|
||||
generate_mcp_endpoints_tools/venv
|
||||
bacon.toml
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE \n workspace_settings\n SET\n error_handler = NULL,\n error_handler_extra_args = NULL,\n error_handler_muted_on_cancel = NULL\n WHERE \n workspace_id = $1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "04f8d738b1073b8c58db0965e8fdcdb872dce2c1872359c1bebb553a29ba1637"
|
||||
}
|
||||
@@ -147,6 +147,16 @@
|
||||
"ordinal": 28,
|
||||
"name": "ducklake",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 29,
|
||||
"name": "auto_add_instance_groups",
|
||||
"type_info": "TextArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 30,
|
||||
"name": "auto_add_instance_groups_roles",
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -183,6 +193,8 @@
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
|
||||
@@ -62,7 +62,8 @@
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java",
|
||||
"duckdb"
|
||||
"duckdb",
|
||||
"ruby"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO flow\n (workspace_id, path, summary, description, archived, extra_perms, dependency_job, draft_only, tag, ws_error_handler_muted, dedicated_worker, timeout, visible_to_runner_only, on_behalf_of_email, concurrency_key, versions, value, schema, edited_by, edited_at) \n SELECT workspace_id, REGEXP_REPLACE(path,'u/' || $2 || '/(.*)','u/' || $1 || '/\\1'), summary, description, archived, extra_perms, dependency_job, draft_only, tag, ws_error_handler_muted, dedicated_worker, timeout, visible_to_runner_only, on_behalf_of_email, concurrency_key, versions, value, schema, edited_by, edited_at\n FROM flow \n WHERE path LIKE ('u/' || $2 || '/%') AND workspace_id = $3",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "0a56301b5aaf57339cb2904c8f617366b74e891034d32f2867ccb019da869fc8"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO usr (workspace_id, username, email, is_admin, operator) VALUES ($1, $2, $3, false, $4) ON CONFLICT DO NOTHING",
|
||||
"query": "INSERT INTO usr (workspace_id, username, email, is_admin, operator, added_via) VALUES ($1, $2, $3, false, $4, $5) ON CONFLICT DO NOTHING",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -8,10 +8,11 @@
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Varchar",
|
||||
"Bool"
|
||||
"Bool",
|
||||
"Jsonb"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "e822d186203fe809b764007ad7c02870a3b7d93ae43b40ac2cd3181dffab0837"
|
||||
"hash": "0d7ce0397ef15c9d6cdaeaa2730a9e27fb7387ca24980df1481e6a94622ef006"
|
||||
}
|
||||
14
backend/.sqlx/query-0fa105c49c8345916716514444bd3616ae4d114216c659233fbbc3c047e6b30a.json
generated
Normal file
14
backend/.sqlx/query-0fa105c49c8345916716514444bd3616ae4d114216c659233fbbc3c047e6b30a.json
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE\n workspace_settings\n SET\n error_handler = NULL,\n error_handler_extra_args = NULL,\n error_handler_muted_on_cancel = NULL\n WHERE\n workspace_id = $1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "0fa105c49c8345916716514444bd3616ae4d114216c659233fbbc3c047e6b30a"
|
||||
}
|
||||
32
backend/.sqlx/query-10f6d3ffd7406146572b1becdce5c8da5242b58f6ce46ab10296cff9d6a3a6c4.json
generated
Normal file
32
backend/.sqlx/query-10f6d3ffd7406146572b1becdce5c8da5242b58f6ce46ab10296cff9d6a3a6c4.json
generated
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT name, summary, array_remove(array_agg(email_to_igroup.email), null) as emails FROM email_to_igroup RIGHT JOIN instance_group ON instance_group.name = email_to_igroup.igroup GROUP BY name, summary",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "name",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "summary",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "emails",
|
||||
"type_info": "VarcharArray"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
true,
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "10f6d3ffd7406146572b1becdce5c8da5242b58f6ce46ab10296cff9d6a3a6c4"
|
||||
}
|
||||
28
backend/.sqlx/query-18ca698813b58c7f93139b12818681f9e36e8bb69b7a37755dc9b90c5e1af4cf.json
generated
Normal file
28
backend/.sqlx/query-18ca698813b58c7f93139b12818681f9e36e8bb69b7a37755dc9b90c5e1af4cf.json
generated
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT tag::text, EXISTS(SELECT 1 FROM worker_ping WHERE custom_tags @> ARRAY[tag] AND ping_at > now() - interval '1 minute') as exists\n FROM unnest($1::text[]) as tag",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "tag",
|
||||
"type_info": "Text"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "exists",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"TextArray"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null,
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "18ca698813b58c7f93139b12818681f9e36e8bb69b7a37755dc9b90c5e1af4cf"
|
||||
}
|
||||
22
backend/.sqlx/query-18e550f4ec23d465632449b88c4b25931f145f771b93828e8e6dfcc1f906443d.json
generated
Normal file
22
backend/.sqlx/query-18e550f4ec23d465632449b88c4b25931f145f771b93828e8e6dfcc1f906443d.json
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT COALESCE(auto_add_instance_groups, '{}') FROM workspace_settings WHERE workspace_id = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "coalesce",
|
||||
"type_info": "TextArray"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "18e550f4ec23d465632449b88c4b25931f145f771b93828e8e6dfcc1f906443d"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "WITH inserted_job AS (\n INSERT INTO v2_job (id, workspace_id, raw_code, raw_lock, raw_flow, tag, parent_job,\n created_by, permissioned_as, runnable_id, runnable_path, args, kind, trigger,\n script_lang, same_worker, pre_run_error, permissioned_as_email, visible_to_owner,\n flow_innermost_root_job, root_job, concurrent_limit, concurrency_time_window_s, timeout, flow_step_id,\n cache_ttl, priority, trigger_kind, script_entrypoint_override, preprocessed)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18,\n $19, $20, $38, $21, $22, $23, $24, $25, $26, $39::job_trigger_kind,\n ($12::JSONB)->>'_ENTRYPOINT_OVERRIDE', $27)\n ),\n inserted_runtime AS (\n INSERT INTO v2_job_runtime (id, ping) VALUES ($1, null)\n ),\n inserted_job_perms AS (\n INSERT INTO job_perms (job_id, email, username, is_admin, is_operator, folders, groups, workspace_id) \n values ($1, $32, $33, $34, $35, $36, $37, $2) \n ON CONFLICT (job_id) DO UPDATE SET email = $32, username = $33, is_admin = $34, is_operator = $35, folders = $36, groups = $37, workspace_id = $2\n )\n INSERT INTO v2_job_queue\n (workspace_id, id, running, scheduled_for, started_at, tag, priority)\n VALUES ($2, $1, $28, COALESCE($29, now()), CASE WHEN $27 THEN now() END, $30, $31)",
|
||||
"query": "WITH inserted_job AS (\n INSERT INTO v2_job (id, workspace_id, raw_code, raw_lock, raw_flow, tag, parent_job,\n created_by, permissioned_as, runnable_id, runnable_path, args, kind, trigger,\n script_lang, same_worker, pre_run_error, permissioned_as_email, visible_to_owner,\n flow_innermost_root_job, root_job, concurrent_limit, concurrency_time_window_s, timeout, flow_step_id,\n cache_ttl, priority, trigger_kind, script_entrypoint_override, preprocessed)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18,\n $19, $20, $38, $21, $22, $23, $24, $25, $26, $39::job_trigger_kind,\n ($12::JSONB)->>'_ENTRYPOINT_OVERRIDE', $27)\n ),\n inserted_runtime AS (\n INSERT INTO v2_job_runtime (id, ping) VALUES ($1, null)\n ),\n inserted_job_perms AS (\n INSERT INTO job_perms (job_id, email, username, is_admin, is_operator, folders, groups, workspace_id) \n values ($1, $32, $33, $34, $35, $36, $37, $2) \n ON CONFLICT (job_id) DO UPDATE SET email = $32, username = $33, is_admin = $34, is_operator = $35, folders = $36, groups = $37, workspace_id = $2\n )\n INSERT INTO v2_job_queue\n (workspace_id, id, running, scheduled_for, started_at, tag, priority)\n VALUES ($2, $1, $28, COALESCE($29, now()), CASE WHEN $27 OR $40 THEN now() END, $30, $31)",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
@@ -39,7 +39,8 @@
|
||||
"singlescriptflow",
|
||||
"flowscript",
|
||||
"flownode",
|
||||
"appscript"
|
||||
"appscript",
|
||||
"aiagent"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -71,7 +72,8 @@
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java",
|
||||
"duckdb"
|
||||
"duckdb",
|
||||
"ruby"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -120,10 +122,11 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"Bool"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "acfe583fe17604ba72ba4800b62a72de0a9de0d58ef8c28dd709adf3be021597"
|
||||
"hash": "193d292c5ed44bf5266ad52c83704c3a36aa284fab3b7e638dbca12ac846b82b"
|
||||
}
|
||||
@@ -43,7 +43,8 @@
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java",
|
||||
"duckdb"
|
||||
"duckdb",
|
||||
"ruby"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
26
backend/.sqlx/query-1b56a720d99a689e80d12ee1efbfeb71d7cd7bb17e936746749c958062cdff9e.json
generated
Normal file
26
backend/.sqlx/query-1b56a720d99a689e80d12ee1efbfeb71d7cd7bb17e936746749c958062cdff9e.json
generated
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT tag AS \"tag!\", count(*) AS \"count!\" FROM v2_job_queue WHERE\n running = true\n GROUP BY tag",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "tag!",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "count!",
|
||||
"type_info": "Int8"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "1b56a720d99a689e80d12ee1efbfeb71d7cd7bb17e936746749c958062cdff9e"
|
||||
}
|
||||
38
backend/.sqlx/query-1e6c125c884002a1565b11a2c308ce89f9726d21bbb3cc712ad0b6450cbb44e6.json
generated
Normal file
38
backend/.sqlx/query-1e6c125c884002a1565b11a2c308ce89f9726d21bbb3cc712ad0b6450cbb44e6.json
generated
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n ig.name as group_name,\n ws.workspace_id,\n w.name as workspace_name,\n ws.auto_add_instance_groups_roles->ig.name as role\n FROM instance_group ig\n INNER JOIN workspace_settings ws ON ws.auto_add_instance_groups IS NOT NULL\n AND ig.name = ANY(ws.auto_add_instance_groups)\n INNER JOIN workspace w ON w.id = ws.workspace_id AND w.deleted = false\n ORDER BY ig.name, ws.workspace_id\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "group_name",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "workspace_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "workspace_name",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "role",
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "1e6c125c884002a1565b11a2c308ce89f9726d21bbb3cc712ad0b6450cbb44e6"
|
||||
}
|
||||
22
backend/.sqlx/query-21099fabde943edc90d3a0125e8490691b2701d11f918da3bb5ae610d5c023a0.json
generated
Normal file
22
backend/.sqlx/query-21099fabde943edc90d3a0125e8490691b2701d11f918da3bb5ae610d5c023a0.json
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT email FROM email_to_igroup WHERE igroup = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "email",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "21099fabde943edc90d3a0125e8490691b2701d11f918da3bb5ae610d5c023a0"
|
||||
}
|
||||
29
backend/.sqlx/query-2132a715995f2775917c59c01ba66f2e472a2347f25cc7109f36a805806ee6e2.json
generated
Normal file
29
backend/.sqlx/query-2132a715995f2775917c59c01ba66f2e472a2347f25cc7109f36a805806ee6e2.json
generated
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT username, added_via\n FROM usr\n WHERE workspace_id = $1 AND email = $2\n AND added_via->>'source' = 'instance_group'\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "username",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "added_via",
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "2132a715995f2775917c59c01ba66f2e472a2347f25cc7109f36a805806ee6e2"
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE \n workspace_settings\n SET\n error_handler = $1,\n error_handler_extra_args = $2,\n error_handler_muted_on_cancel = $3\n WHERE \n workspace_id = $4\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Json",
|
||||
"Bool",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "2549197c6750bb1a20041b2d7c2654a788a32a9282ed314c2b3bcafe6550efca"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT label,\n concat(substring(token for 10)) AS token_prefix,\n expiration,\n created_at,\n last_used_at,\n scopes,\n email\n FROM token\n WHERE workspace_id = $1\n AND (\n scopes @> ARRAY['jobs:run:scripts:' || $2]::text[]\n OR scopes @> ARRAY['run:scripts/' || $2]::text[]\n )\n ",
|
||||
"query": "\n SELECT label,\n concat(substring(token for 10)) AS token_prefix,\n expiration,\n created_at,\n last_used_at,\n scopes,\n email\n FROM token\n WHERE workspace_id = $1\n AND (\n scopes @> ARRAY['jobs:run:scripts:' || $2]::text[]\n OR scopes @> ARRAY['run:script/' || $2]::text[]\n )\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -55,5 +55,5 @@
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "e8b74683f994d198a051c2f211a2844241bf2a7d7702c569017ae53fca706c59"
|
||||
"hash": "29673d489fbf45fc249da04c1a2fd60e2364ba87263f962ed7d4329c916620a1"
|
||||
}
|
||||
14
backend/.sqlx/query-31db242523c534b2abbb5f4985f56dd4493d19611ed988d694d9f4289dc29c48.json
generated
Normal file
14
backend/.sqlx/query-31db242523c534b2abbb5f4985f56dd4493d19611ed988d694d9f4289dc29c48.json
generated
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE workspace_settings SET auto_add_instance_groups = NULL, auto_add_instance_groups_roles = NULL WHERE workspace_id = $1",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "31db242523c534b2abbb5f4985f56dd4493d19611ed988d694d9f4289dc29c48"
|
||||
}
|
||||
16
backend/.sqlx/query-3e3afba04a10f16606e17cea6b31d9578cac41b76092722fd2698afb4cf08834.json
generated
Normal file
16
backend/.sqlx/query-3e3afba04a10f16606e17cea6b31d9578cac41b76092722fd2698afb4cf08834.json
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE v2_job_status SET\n flow_status = jsonb_set(\n flow_status,\n array['modules', $2::TEXT, 'agent_actions_success'],\n COALESCE(\n flow_status->'modules'->$2->'agent_actions_success',\n to_jsonb(ARRAY[]::bool[])\n ) || to_jsonb(ARRAY[$3::bool])\n )\n WHERE id = $1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Text",
|
||||
"Bool"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "3e3afba04a10f16606e17cea6b31d9578cac41b76092722fd2698afb4cf08834"
|
||||
}
|
||||
28
backend/.sqlx/query-3ebc91867be0a4830ef4dbbe833aed348f78e3cb68fb1f3c855a491bdcda5017.json
generated
Normal file
28
backend/.sqlx/query-3ebc91867be0a4830ef4dbbe833aed348f78e3cb68fb1f3c855a491bdcda5017.json
generated
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT\n workspace_id,\n auto_add_instance_groups_roles\n FROM workspace_settings\n WHERE\n auto_add_instance_groups IS NOT NULL\n AND $1 = ANY(auto_add_instance_groups)\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "workspace_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "auto_add_instance_groups_roles",
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "3ebc91867be0a4830ef4dbbe833aed348f78e3cb68fb1f3c855a491bdcda5017"
|
||||
}
|
||||
@@ -28,7 +28,8 @@
|
||||
"singlescriptflow",
|
||||
"flowscript",
|
||||
"flownode",
|
||||
"appscript"
|
||||
"appscript",
|
||||
"aiagent"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT usr.username \n FROM usr_to_group LEFT JOIN usr ON usr_to_group.usr = usr.username AND usr_to_group.workspace_id = $2\n WHERE group_ = $1 AND usr.workspace_id = $2 AND usr_to_group.workspace_id = $2",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "username",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "3fdfcab1a54c166b1d8d43215d61268a251160db4630f0342522091668f36af0"
|
||||
}
|
||||
16
backend/.sqlx/query-404233e74aaafd987879c6c87d1fd80928e6fade09e60a9a2d35121c81885cca.json
generated
Normal file
16
backend/.sqlx/query-404233e74aaafd987879c6c87d1fd80928e6fade09e60a9a2d35121c81885cca.json
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE workspace_settings SET auto_add_instance_groups = $2, auto_add_instance_groups_roles = $3 WHERE workspace_id = $1",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"TextArray",
|
||||
"Jsonb"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "404233e74aaafd987879c6c87d1fd80928e6fade09e60a9a2d35121c81885cca"
|
||||
}
|
||||
35
backend/.sqlx/query-472f224dc9e17d2c50cb9db13c34cc1fb9adb6d0ea36cf223541adb7cac17bdd.json
generated
Normal file
35
backend/.sqlx/query-472f224dc9e17d2c50cb9db13c34cc1fb9adb6d0ea36cf223541adb7cac17bdd.json
generated
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT workspace_id, username, email\n FROM usr\n WHERE email = $1\n AND added_via->>'source' = 'instance_group'\n AND added_via->>'group' = $2\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "workspace_id",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "username",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "email",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "472f224dc9e17d2c50cb9db13c34cc1fb9adb6d0ea36cf223541adb7cac17bdd"
|
||||
}
|
||||
@@ -32,7 +32,8 @@
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java",
|
||||
"duckdb"
|
||||
"duckdb",
|
||||
"ruby"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
"singlescriptflow",
|
||||
"flowscript",
|
||||
"flownode",
|
||||
"appscript"
|
||||
"appscript",
|
||||
"aiagent"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -71,7 +72,8 @@
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java",
|
||||
"duckdb"
|
||||
"duckdb",
|
||||
"ruby"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
15
backend/.sqlx/query-4a446b97cf813226d25ca40cefca2999cdcf938f817327e9168b3edb0fce7fb7.json
generated
Normal file
15
backend/.sqlx/query-4a446b97cf813226d25ca40cefca2999cdcf938f817327e9168b3edb0fce7fb7.json
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE workspace_settings SET\n auto_add_instance_groups = array_remove(auto_add_instance_groups, $1),\n auto_add_instance_groups_roles = auto_add_instance_groups_roles - $1\n WHERE workspace_id = $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "4a446b97cf813226d25ca40cefca2999cdcf938f817327e9168b3edb0fce7fb7"
|
||||
}
|
||||
@@ -68,7 +68,8 @@
|
||||
"singlescriptflow",
|
||||
"flowscript",
|
||||
"flownode",
|
||||
"appscript"
|
||||
"appscript",
|
||||
"aiagent"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -138,7 +139,8 @@
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java",
|
||||
"duckdb"
|
||||
"duckdb",
|
||||
"ruby"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
15
backend/.sqlx/query-4fb3881cdbb4b9e93e28f460a9b3715bdc6a52b76c89f3a3913023b13c4e085c.json
generated
Normal file
15
backend/.sqlx/query-4fb3881cdbb4b9e93e28f460a9b3715bdc6a52b76c89f3a3913023b13c4e085c.json
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO pip_resolution_cache (hash, lockfile, expiration) VALUES ($1, $2, now() + ('3 days')::interval) ON CONFLICT (hash) DO UPDATE SET lockfile = $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "4fb3881cdbb4b9e93e28f460a9b3715bdc6a52b76c89f3a3913023b13c4e085c"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT usage.usage FROM usage \n WHERE is_workspace = false \n AND month_ = EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date)\n AND id = $1",
|
||||
"query": "\n SELECT usage.usage FROM usage\n WHERE is_workspace = false\n AND month_ = EXTRACT(YEAR FROM current_date) * 12 + EXTRACT(MONTH FROM current_date)\n AND id = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -18,5 +18,5 @@
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "a7b028e832396ee4d1ad6dfd44ba6134344f3eb37dbf0254154eba31b9cc2ed3"
|
||||
"hash": "51cfe6efb154934f8cfbe77a7313891ef5c46a7febe4125d164a5ae5b55af2d6"
|
||||
}
|
||||
@@ -147,6 +147,16 @@
|
||||
"ordinal": 28,
|
||||
"name": "ducklake",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 29,
|
||||
"name": "auto_add_instance_groups",
|
||||
"type_info": "TextArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 30,
|
||||
"name": "auto_add_instance_groups_roles",
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -183,6 +193,8 @@
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT EXISTS(SELECT 1 FROM worker_ping WHERE custom_tags @> $1 AND ping_at > now() - interval '1 minute')",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "exists",
|
||||
"type_info": "Bool"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"TextArray"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "5d1ec728380ea8baf64df54743e73008ee9a58e6f39a5bf31a2ed099727f5c04"
|
||||
}
|
||||
@@ -42,6 +42,11 @@
|
||||
"ordinal": 7,
|
||||
"name": "role",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "added_via",
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -57,6 +62,7 @@
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
|
||||
@@ -42,6 +42,11 @@
|
||||
"ordinal": 7,
|
||||
"name": "role",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "added_via",
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -58,6 +63,7 @@
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
|
||||
@@ -62,7 +62,8 @@
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java",
|
||||
"duckdb"
|
||||
"duckdb",
|
||||
"ruby"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT label,\n concat(substring(token for 10)) AS token_prefix,\n expiration,\n created_at,\n last_used_at,\n scopes,\n email\n FROM token\n WHERE workspace_id = $1\n AND (\n scopes @> ARRAY['jobs:run:flows:' || $2]::text[]\n OR scopes @> ARRAY['run:flows/' || $2]::text[]\n )\n ",
|
||||
"query": "\n SELECT label,\n concat(substring(token for 10)) AS token_prefix,\n expiration,\n created_at,\n last_used_at,\n scopes,\n email\n FROM token\n WHERE workspace_id = $1\n AND (\n scopes @> ARRAY['jobs:run:flows:' || $2]::text[]\n OR scopes @> ARRAY['run:flow/' || $2]::text[]\n )\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -55,5 +55,5 @@
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "334c9a6d770471ac53099eb5227778899a5c680b899bc6a6d1a3f89fdbf8c730"
|
||||
"hash": "6a254de9005594dc75a59a545546417c8a5aa7635be1dc0b37dc29d0f9e7c163"
|
||||
}
|
||||
@@ -45,11 +45,16 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "added_via",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"name": "super_admin",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"ordinal": 10,
|
||||
"name": "name",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
@@ -69,6 +74,7 @@
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true
|
||||
]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT EXISTS(SELECT 1 FROM group_ WHERE (group_.extra_perms ->> CONCAT('u/', $1::text))::boolean AND name = $2 AND workspace_id = $4) OR exists(\n SELECT 1 FROM group_ g, jsonb_each_text(g.extra_perms) f \n WHERE $2 = g.name AND $4 = g.workspace_id AND SPLIT_PART(key, '/', 1) = 'g' AND key = ANY($3::text[])\n AND value::boolean)",
|
||||
"query": "SELECT EXISTS(SELECT 1 FROM group_ WHERE (group_.extra_perms ->> CONCAT('u/', $1::text))::boolean AND name = $2 AND workspace_id = $4) OR exists(\n SELECT 1 FROM group_ g, jsonb_each_text(g.extra_perms) f\n WHERE $2 = g.name AND $4 = g.workspace_id AND SPLIT_PART(key, '/', 1) = 'g' AND key = ANY($3::text[])\n AND value::boolean)",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -21,5 +21,5 @@
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "388d6fd335a3f8a405b2d465892cf21a68d4b50ace25ef88c4cdf5b347c3d5eb"
|
||||
"hash": "6b2820973026b1628cb93fda943bc389a261a3bb975c86ac02dd1c552da92295"
|
||||
}
|
||||
30
backend/.sqlx/query-6df2ca52e3e8515c398943da701600a33e64525809fdd67bce63e28d98eababc.json
generated
Normal file
30
backend/.sqlx/query-6df2ca52e3e8515c398943da701600a33e64525809fdd67bce63e28d98eababc.json
generated
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT created_by AS \"created_by!\", coalesce(job_logs.logs, '') as logs\n FROM v2_job\n LEFT JOIN job_logs ON job_logs.job_id = v2_job.id\n WHERE v2_job.id = $1 AND v2_job.workspace_id = $2 AND ($3::text[] IS NULL OR v2_job.tag = ANY($3))\n ORDER BY job_logs.log_offset DESC\n LIMIT 100",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "created_by!",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "logs",
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Text",
|
||||
"TextArray"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "6df2ca52e3e8515c398943da701600a33e64525809fdd67bce63e28d98eababc"
|
||||
}
|
||||
23
backend/.sqlx/query-6f36c05e6097066441acab227c0d5206d5a9a9828b04e4c107f1ecab4a9363d4.json
generated
Normal file
23
backend/.sqlx/query-6f36c05e6097066441acab227c0d5206d5a9a9828b04e4c107f1ecab4a9363d4.json
generated
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT usr.username\n FROM usr_to_group LEFT JOIN usr ON usr_to_group.usr = usr.username AND usr_to_group.workspace_id = $2\n WHERE group_ = $1 AND usr.workspace_id = $2 AND usr_to_group.workspace_id = $2",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "username",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "6f36c05e6097066441acab227c0d5206d5a9a9828b04e4c107f1ecab4a9363d4"
|
||||
}
|
||||
22
backend/.sqlx/query-711c72a72298bb656882b35071e910dab721cda070f9c39bba3729bdc1467496.json
generated
Normal file
22
backend/.sqlx/query-711c72a72298bb656882b35071e910dab721cda070f9c39bba3729bdc1467496.json
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT workspace_id FROM workspace_settings WHERE auto_add_instance_groups IS NOT NULL AND $1 = ANY(auto_add_instance_groups)",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "workspace_id",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "711c72a72298bb656882b35071e910dab721cda070f9c39bba3729bdc1467496"
|
||||
}
|
||||
@@ -98,7 +98,8 @@
|
||||
"singlescriptflow",
|
||||
"flowscript",
|
||||
"flownode",
|
||||
"appscript"
|
||||
"appscript",
|
||||
"aiagent"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -148,7 +149,8 @@
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java",
|
||||
"duckdb"
|
||||
"duckdb",
|
||||
"ruby"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,8 @@
|
||||
"singlescriptflow",
|
||||
"flowscript",
|
||||
"flownode",
|
||||
"appscript"
|
||||
"appscript",
|
||||
"aiagent"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,8 @@
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java",
|
||||
"duckdb"
|
||||
"duckdb",
|
||||
"ruby"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
61
backend/.sqlx/query-805d633de90fee335f1726284eda0dbc200d45960fb8dea867492c8c7dd096d5.json
generated
Normal file
61
backend/.sqlx/query-805d633de90fee335f1726284eda0dbc200d45960fb8dea867492c8c7dd096d5.json
generated
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT runnable_id as \"runnable_id: ScriptHash\", raw_flow as \"raw_flow: _\", kind as \"kind: _\" FROM v2_job WHERE id = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "runnable_id: ScriptHash",
|
||||
"type_info": "Int8"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "raw_flow: _",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "kind: _",
|
||||
"type_info": {
|
||||
"Custom": {
|
||||
"name": "job_kind",
|
||||
"kind": {
|
||||
"Enum": [
|
||||
"script",
|
||||
"preview",
|
||||
"flow",
|
||||
"dependencies",
|
||||
"flowpreview",
|
||||
"script_hub",
|
||||
"identity",
|
||||
"flowdependencies",
|
||||
"http",
|
||||
"graphql",
|
||||
"postgresql",
|
||||
"noop",
|
||||
"appdependencies",
|
||||
"deploymentcallback",
|
||||
"singlescriptflow",
|
||||
"flowscript",
|
||||
"flownode",
|
||||
"appscript",
|
||||
"aiagent"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
true,
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "805d633de90fee335f1726284eda0dbc200d45960fb8dea867492c8c7dd096d5"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT usr.email, usage.executions\n FROM usr\n , LATERAL (\n SELECT COALESCE(SUM(duration_ms + 1000)/1000 , 0)::BIGINT executions\n FROM v2_as_completed_job\n WHERE workspace_id = $1\n AND job_kind NOT IN ('flow', 'flowpreview', 'flownode')\n AND email = usr.email\n AND now() - '1 week'::interval < created_at \n ) usage\n WHERE workspace_id = $1\n ",
|
||||
"query": "\n SELECT usr.email, usage.executions\n FROM usr\n , LATERAL (\n SELECT COALESCE(SUM(duration_ms + 1000)/1000 , 0)::BIGINT executions\n FROM v2_as_completed_job\n WHERE workspace_id = $1\n AND job_kind NOT IN ('flow', 'flowpreview', 'flownode')\n AND email = usr.email\n AND now() - '1 week'::interval < created_at\n ) usage\n WHERE workspace_id = $1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -24,5 +24,5 @@
|
||||
null
|
||||
]
|
||||
},
|
||||
"hash": "bff39cc57aba0729ddef1d53f3806c6736556f0a14b489d6708f9879393f9ea3"
|
||||
"hash": "89940a53f29b173b6a8717f057a81a4f2edad152581950fdd80d758a0d242c17"
|
||||
}
|
||||
@@ -28,7 +28,8 @@
|
||||
"singlescriptflow",
|
||||
"flowscript",
|
||||
"flownode",
|
||||
"appscript"
|
||||
"appscript",
|
||||
"aiagent"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
15
backend/.sqlx/query-94feb54cc965f19bfaf09966fd431b925c565f08c100bea812d3ac0e28664ccb.json
generated
Normal file
15
backend/.sqlx/query-94feb54cc965f19bfaf09966fd431b925c565f08c100bea812d3ac0e28664ccb.json
generated
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE usr SET is_admin = true WHERE workspace_id = $1 AND email = $2",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "94feb54cc965f19bfaf09966fd431b925c565f08c100bea812d3ac0e28664ccb"
|
||||
}
|
||||
22
backend/.sqlx/query-9530b234b2ac8f7360552be5e6bb25270e6b4185ce5c7f3c6edd9fbaabf77544.json
generated
Normal file
22
backend/.sqlx/query-9530b234b2ac8f7360552be5e6bb25270e6b4185ce5c7f3c6edd9fbaabf77544.json
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT DISTINCT email FROM usr WHERE added_via->>'source' = 'instance_group' AND added_via->>'group' = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "email",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "9530b234b2ac8f7360552be5e6bb25270e6b4185ce5c7f3c6edd9fbaabf77544"
|
||||
}
|
||||
17
backend/.sqlx/query-97b6e5779661343587c297b275df9e75fd22924ad2dbe124bb361f3e7fd8bfe0.json
generated
Normal file
17
backend/.sqlx/query-97b6e5779661343587c297b275df9e75fd22924ad2dbe124bb361f3e7fd8bfe0.json
generated
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE\n workspace_settings\n SET\n error_handler = $1,\n error_handler_extra_args = $2,\n error_handler_muted_on_cancel = $3\n WHERE\n workspace_id = $4\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Varchar",
|
||||
"Json",
|
||||
"Bool",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "97b6e5779661343587c297b275df9e75fd22924ad2dbe124bb361f3e7fd8bfe0"
|
||||
}
|
||||
16
backend/.sqlx/query-9a923c85a015e4149328f650e77872a1c39d5992efd6abd2d3b8a558d7b884a1.json
generated
Normal file
16
backend/.sqlx/query-9a923c85a015e4149328f650e77872a1c39d5992efd6abd2d3b8a558d7b884a1.json
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n UPDATE v2_job_status SET\n flow_status = jsonb_set(\n flow_status,\n array['modules', $3::TEXT, 'agent_actions'],\n $2\n )\n WHERE id = $1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Uuid",
|
||||
"Jsonb",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "9a923c85a015e4149328f650e77872a1c39d5992efd6abd2d3b8a558d7b884a1"
|
||||
}
|
||||
@@ -98,7 +98,8 @@
|
||||
"singlescriptflow",
|
||||
"flowscript",
|
||||
"flownode",
|
||||
"appscript"
|
||||
"appscript",
|
||||
"aiagent"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -148,7 +149,8 @@
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java",
|
||||
"duckdb"
|
||||
"duckdb",
|
||||
"ruby"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,8 @@
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java",
|
||||
"duckdb"
|
||||
"duckdb",
|
||||
"ruby"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,8 @@
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java",
|
||||
"duckdb"
|
||||
"duckdb",
|
||||
"ruby"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,8 @@
|
||||
"singlescriptflow",
|
||||
"flowscript",
|
||||
"flownode",
|
||||
"appscript"
|
||||
"appscript",
|
||||
"aiagent"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -66,7 +67,8 @@
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java",
|
||||
"duckdb"
|
||||
"duckdb",
|
||||
"ruby"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT \n workspace_id,\n slack_team_id,\n teams_team_id,\n teams_team_name,\n slack_name,\n slack_command_script,\n teams_command_script,\n slack_email,\n auto_invite_domain,\n auto_invite_operator,\n auto_add,\n customer_id,\n plan,\n webhook,\n deploy_to,\n ai_config,\n error_handler,\n error_handler_extra_args,\n error_handler_muted_on_cancel,\n large_file_storage,\n ducklake,\n git_sync,\n deploy_ui,\n default_app,\n default_scripts,\n mute_critical_alerts,\n color,\n operator_settings,\n git_app_installations\n FROM \n workspace_settings\n WHERE \n workspace_id = $1\n ",
|
||||
"query": "\n SELECT\n workspace_id,\n slack_team_id,\n teams_team_id,\n teams_team_name,\n slack_name,\n slack_command_script,\n teams_command_script,\n slack_email,\n auto_invite_domain,\n auto_invite_operator,\n auto_add,\n customer_id,\n plan,\n webhook,\n deploy_to,\n ai_config,\n error_handler,\n error_handler_extra_args,\n error_handler_muted_on_cancel,\n large_file_storage,\n ducklake,\n git_sync,\n deploy_ui,\n default_app,\n default_scripts,\n mute_critical_alerts,\n color,\n operator_settings,\n git_app_installations,\n auto_add_instance_groups,\n auto_add_instance_groups_roles\n FROM\n workspace_settings\n WHERE\n workspace_id = $1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -147,6 +147,16 @@
|
||||
"ordinal": 28,
|
||||
"name": "git_app_installations",
|
||||
"type_info": "Jsonb"
|
||||
},
|
||||
{
|
||||
"ordinal": 29,
|
||||
"name": "auto_add_instance_groups",
|
||||
"type_info": "TextArray"
|
||||
},
|
||||
{
|
||||
"ordinal": 30,
|
||||
"name": "auto_add_instance_groups_roles",
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -183,8 +193,10 @@
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false
|
||||
false,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "8960b73f0d3cbfa0729d24ecbe3f635592feee6a5724fdff662c6ac1f3c6ddc8"
|
||||
"hash": "ac1fd12e9ec92022be38aee0e91e9002e0e810d0e76dce5ced1000a7cb514adb"
|
||||
}
|
||||
@@ -33,7 +33,8 @@
|
||||
"singlescriptflow",
|
||||
"flowscript",
|
||||
"flownode",
|
||||
"appscript"
|
||||
"appscript",
|
||||
"aiagent"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
"Left": []
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
true
|
||||
true,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76"
|
||||
|
||||
40
backend/.sqlx/query-b45e17ad532a23b394226c9a5d7ab5a21e20202dbbf9c67831cc62eb067cd2ba.json
generated
Normal file
40
backend/.sqlx/query-b45e17ad532a23b394226c9a5d7ab5a21e20202dbbf9c67831cc62eb067cd2ba.json
generated
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT v2_job_queue.id, v2_job.tag, v2_job_queue.scheduled_for, v2_job_queue.workspace_id FROM v2_job_queue LEFT JOIN v2_job ON v2_job_queue.id = v2_job.id WHERE running = false AND scheduled_for < now() - ($1 || ' minutes')::interval",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "id",
|
||||
"type_info": "Uuid"
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "tag",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "scheduled_for",
|
||||
"type_info": "Timestamptz"
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "workspace_id",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "b45e17ad532a23b394226c9a5d7ab5a21e20202dbbf9c67831cc62eb067cd2ba"
|
||||
}
|
||||
16
backend/.sqlx/query-c269f14ae9ae4e96eff9483eb84cccbdfa316e5db051f1d52085a2d5447c81ae.json
generated
Normal file
16
backend/.sqlx/query-c269f14ae9ae4e96eff9483eb84cccbdfa316e5db051f1d52085a2d5447c81ae.json
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO flow\n (workspace_id, path, summary, description, archived, extra_perms, dependency_job, draft_only, tag, ws_error_handler_muted, dedicated_worker, timeout, visible_to_runner_only, on_behalf_of_email, concurrency_key, versions, value, schema, edited_by, edited_at)\n SELECT workspace_id, REGEXP_REPLACE(path,'u/' || $2 || '/(.*)','u/' || $1 || '/\\1'), summary, description, archived, extra_perms, dependency_job, draft_only, tag, ws_error_handler_muted, dedicated_worker, timeout, visible_to_runner_only, on_behalf_of_email, concurrency_key, versions, value, schema, edited_by, edited_at\n FROM flow\n WHERE path LIKE ('u/' || $2 || '/%') AND workspace_id = $3",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text",
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "c269f14ae9ae4e96eff9483eb84cccbdfa316e5db051f1d52085a2d5447c81ae"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "SELECT flow.workspace_id as workspace, flow.path, summary, description, flow_version.schema \n FROM flow \n LEFT JOIN flow_version ON flow_version.id = flow.versions[array_upper(flow.versions, 1)]\n WHERE flow.workspace_id = $1",
|
||||
"query": "SELECT flow.workspace_id as workspace, flow.path, summary, description, flow_version.schema\n FROM flow\n LEFT JOIN flow_version ON flow_version.id = flow.versions[array_upper(flow.versions, 1)]\n WHERE flow.workspace_id = $1",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -42,5 +42,5 @@
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "974c7e623f3dfa440e134eaaa8d029334c0645147200219c39b2c00b30941172"
|
||||
"hash": "ccbf71572dfc60b69a1666d4f1a883ba724d1e9c3303df32b001737b80a4b9f9"
|
||||
}
|
||||
@@ -42,6 +42,11 @@
|
||||
"ordinal": 7,
|
||||
"name": "role",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "added_via",
|
||||
"type_info": "Jsonb"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -57,6 +62,7 @@
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
|
||||
22
backend/.sqlx/query-ee182378d9a760c3593b483703ec1682488ca9e6e402ec41abaa6ae3ca263854.json
generated
Normal file
22
backend/.sqlx/query-ee182378d9a760c3593b483703ec1682488ca9e6e402ec41abaa6ae3ca263854.json
generated
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "\n SELECT email_to_igroup.email\n FROM email_to_igroup\n INNER JOIN instance_group ON instance_group.name = email_to_igroup.igroup\n WHERE instance_group.name = $1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "email",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "ee182378d9a760c3593b483703ec1682488ca9e6e402ec41abaa6ae3ca263854"
|
||||
}
|
||||
16
backend/.sqlx/query-f582cac90b4b7d732956b74eebc51323ef8acd3f627e7517451fcc72998d22bc.json
generated
Normal file
16
backend/.sqlx/query-f582cac90b4b7d732956b74eebc51323ef8acd3f627e7517451fcc72998d22bc.json
generated
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE usr SET added_via = $1 WHERE workspace_id = $2 AND email = $3",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Left": [
|
||||
"Jsonb",
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "f582cac90b4b7d732956b74eebc51323ef8acd3f627e7517451fcc72998d22bc"
|
||||
}
|
||||
@@ -35,7 +35,8 @@
|
||||
"singlescriptflow",
|
||||
"flowscript",
|
||||
"flownode",
|
||||
"appscript"
|
||||
"appscript",
|
||||
"aiagent"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -66,7 +67,8 @@
|
||||
"oracledb",
|
||||
"nu",
|
||||
"java",
|
||||
"duckdb"
|
||||
"duckdb",
|
||||
"ruby"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
1151
backend/Cargo.lock
generated
1151
backend/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "windmill"
|
||||
version = "1.520.1"
|
||||
version = "1.530.0"
|
||||
authors.workspace = true
|
||||
edition.workspace = true
|
||||
|
||||
@@ -24,6 +24,7 @@ members = [
|
||||
"./parsers/windmill-parser-csharp",
|
||||
"./parsers/windmill-parser-nu",
|
||||
"./parsers/windmill-parser-java",
|
||||
"./parsers/windmill-parser-ruby",
|
||||
"./parsers/windmill-parser-bash",
|
||||
"./parsers/windmill-parser-py",
|
||||
"./parsers/windmill-parser-py-imports",
|
||||
@@ -32,7 +33,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "1.520.1"
|
||||
version = "1.530.0"
|
||||
authors = ["Ruben Fiszel <ruben@windmill.dev>"]
|
||||
edition = "2021"
|
||||
|
||||
@@ -95,7 +96,8 @@ php = ["windmill-worker/php"]
|
||||
csharp = ["windmill-worker/csharp"]
|
||||
nu = ["windmill-worker/nu"]
|
||||
java = ["windmill-worker/java"]
|
||||
all_languages = ["python", "deno_core", "rust", "mysql", "oracledb", "duckdb", "mssql", "bigquery", "csharp", "nu", "php", "java"]
|
||||
ruby = ["windmill-worker/ruby"]
|
||||
all_languages = ["python", "deno_core", "rust", "mysql", "oracledb", "duckdb", "mssql", "bigquery", "csharp", "nu", "php", "java", "ruby"]
|
||||
# For windows we have another set of languages enabled
|
||||
# NOTE: DuckDB is ignored because of compilation problems
|
||||
all_languages_windows = ["python", "deno_core", "rust", "mysql", "oracledb", "mssql", "bigquery", "csharp", "nu", "php", "java"]
|
||||
@@ -144,7 +146,8 @@ pep440_rs.workspace = true
|
||||
systemstat.workspace = true
|
||||
size.workspace = true
|
||||
strum.workspace = true
|
||||
|
||||
kube.workspace = true
|
||||
k8s-openapi.workspace = true
|
||||
|
||||
[target.'cfg(not(target_env = "msvc"))'.dependencies]
|
||||
tikv-jemallocator = { optional = true, workspace = true }
|
||||
@@ -180,6 +183,7 @@ windmill-parser-rust = { path = "./parsers/windmill-parser-rust" }
|
||||
windmill-parser-yaml = { path = "./parsers/windmill-parser-yaml" }
|
||||
windmill-parser-csharp = { path = "./parsers/windmill-parser-csharp" }
|
||||
windmill-parser-java = { path = "./parsers/windmill-parser-java" }
|
||||
windmill-parser-ruby = { path = "./parsers/windmill-parser-ruby" }
|
||||
windmill-parser-nu = { path = "./parsers/windmill-parser-nu" }
|
||||
windmill-parser-bash = { path = "./parsers/windmill-parser-bash" }
|
||||
windmill-parser-sql = { path = "./parsers/windmill-parser-sql" }
|
||||
@@ -393,6 +397,8 @@ systemstat = "0.2.4"
|
||||
size = "0.5.0"
|
||||
|
||||
flume = { version = "0.11.1", features = ["async"] }
|
||||
kube = { version = "1.1.0", features = ["runtime", "derive"] }
|
||||
k8s-openapi = { version = "0.25.0", features = ["latest"] }
|
||||
|
||||
# Macro-related
|
||||
proc-macro2 = "1.0"
|
||||
@@ -406,8 +412,8 @@ tokio-tungstenite = { version = "0.24.0", features = ["native-tls"] }
|
||||
tree-sitter = { version = "0.23.0", features = [] }
|
||||
tree-sitter-c-sharp = "0.23.0"
|
||||
tree-sitter-java = "0.23.0"
|
||||
tree-sitter-ruby = "0.23.0"
|
||||
oracle = { version = "0.6.3", features = ["chrono"] }
|
||||
rumqttc = { version = "0.24.0", features = ["use-native-tls"]}
|
||||
strum = { version = "0.27", features = ["derive"] }
|
||||
strum_macros = "^0"
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
3c4027125e0b512b7d322374e83594cd776a9086
|
||||
15a7592ca66b93b9760d49e58b23c090ead06fe2
|
||||
|
||||
@@ -9,6 +9,25 @@ import sys
|
||||
from pathlib import Path
|
||||
from typing import Dict, List, Any, Optional
|
||||
|
||||
IMPORTS = """
|
||||
use std::borrow::Cow;
|
||||
use serde::{Deserialize, Serialize};
|
||||
"""
|
||||
|
||||
ENDPOINT_STRUCT = """
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct EndpointTool {
|
||||
pub name: Cow<'static, str>,
|
||||
pub description: Cow<'static, str>,
|
||||
pub instructions: Cow<'static, str>,
|
||||
pub path: Cow<'static, str>,
|
||||
pub method: Cow<'static, str>,
|
||||
pub path_params_schema: Option<serde_json::Value>,
|
||||
pub query_params_schema: Option<serde_json::Value>,
|
||||
pub body_schema: Option<serde_json::Value>,
|
||||
}
|
||||
"""
|
||||
|
||||
def load_openapi_spec(file_path: str) -> Dict[str, Any]:
|
||||
"""Load and parse the OpenAPI YAML specification."""
|
||||
try:
|
||||
@@ -22,7 +41,7 @@ def load_openapi_spec(file_path: str) -> Dict[str, Any]:
|
||||
print(f"Error loading OpenAPI spec: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
def extract_separate_schemas(parameters: List[Dict[str, Any]], request_body: Optional[Dict[str, Any]], spec: Dict[str, Any]) -> tuple:
|
||||
def extract_separate_schemas(parameters: List[Dict[str, Any]], request_body: Optional[Dict[str, Any]], spec: Dict[str, Any], required_fields: Optional[List[str]] = None) -> tuple:
|
||||
"""Extract separate schemas for path parameters, query parameters, and request body."""
|
||||
path_params_schema = {
|
||||
"type": "object",
|
||||
@@ -73,6 +92,20 @@ def extract_separate_schemas(parameters: List[Dict[str, Any]], request_body: Opt
|
||||
# Process request body if present
|
||||
if request_body:
|
||||
body_schema = extract_request_body_schema(request_body, spec)
|
||||
|
||||
# If we have required fields specified and a body schema, update the required array
|
||||
if body_schema and required_fields:
|
||||
if 'required' not in body_schema:
|
||||
body_schema['required'] = []
|
||||
|
||||
# Add each required field if it exists in the schema properties
|
||||
for field in required_fields:
|
||||
if 'properties' in body_schema and field in body_schema['properties']:
|
||||
if field not in body_schema['required']:
|
||||
body_schema['required'].append(field)
|
||||
else:
|
||||
# Log warning when a required field is missing from schema properties
|
||||
print(f"Warning: Required field '{field}' not found in body schema properties", file=sys.stderr)
|
||||
|
||||
# Return None for empty schemas
|
||||
path_params_schema = path_params_schema if path_params_schema['properties'] else None
|
||||
@@ -180,6 +213,7 @@ def find_mcp_tools(spec: Dict[str, Any]) -> List[Dict[str, Any]]:
|
||||
'method': method.upper(),
|
||||
'parameters': operation.get('parameters', []),
|
||||
'requestBody': operation.get('requestBody'),
|
||||
'required_fields': operation.get('x-mcp-required-fields', []),
|
||||
}
|
||||
tools.append(tool)
|
||||
|
||||
@@ -190,20 +224,8 @@ def generate_rust_code(tools: List[Dict[str, Any]], spec: Dict[str, Any]) -> str
|
||||
if not tools:
|
||||
return """// No MCP tools found in the OpenAPI specification
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EndpointTool {
|
||||
pub name: Cow<'static, str>,
|
||||
pub description: Cow<'static, str>,
|
||||
pub instructions: Cow<'static, str>,
|
||||
pub path: Cow<'static, str>,
|
||||
pub method: http::Method,
|
||||
pub path_params_schema: Option<serde_json::Value>,
|
||||
pub query_params_schema: Option<serde_json::Value>,
|
||||
pub body_schema: Option<serde_json::Value>,
|
||||
}
|
||||
|
||||
{IMPORTS}
|
||||
{ENDPOINT_STRUCT}
|
||||
pub fn all_tools() -> Vec<EndpointTool> {
|
||||
vec![]
|
||||
}
|
||||
@@ -216,11 +238,11 @@ pub fn all_tools() -> Vec<EndpointTool> {
|
||||
description = tool['description']
|
||||
instructions = tool['instructions']
|
||||
path = tool['path']
|
||||
method = http_method_to_rust(tool['method'])
|
||||
method = tool['method'].upper()
|
||||
|
||||
# Generate separate schemas
|
||||
path_params_schema, query_params_schema, body_schema = extract_separate_schemas(
|
||||
tool['parameters'], tool['requestBody'], spec
|
||||
tool['parameters'], tool['requestBody'], spec, tool['required_fields']
|
||||
)
|
||||
|
||||
path_params_rust = schema_to_rust_value(path_params_schema)
|
||||
@@ -233,7 +255,7 @@ pub fn all_tools() -> Vec<EndpointTool> {
|
||||
description: Cow::Borrowed("{description}"),
|
||||
instructions: Cow::Borrowed("{instructions}"),
|
||||
path: Cow::Borrowed("{path}"),
|
||||
method: {method},
|
||||
method: Cow::Borrowed("{method}"),
|
||||
path_params_schema: {path_params_rust},
|
||||
query_params_schema: {query_params_rust},
|
||||
body_schema: {body_schema_rust},
|
||||
@@ -246,20 +268,8 @@ pub fn all_tools() -> Vec<EndpointTool> {
|
||||
rust_code = f"""// Auto-generated MCP tools from OpenAPI specification
|
||||
// This file is generated by generate_mcp_tools.py - DO NOT EDIT MANUALLY
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EndpointTool {{
|
||||
pub name: Cow<'static, str>,
|
||||
pub description: Cow<'static, str>,
|
||||
pub instructions: Cow<'static, str>,
|
||||
pub path: Cow<'static, str>,
|
||||
pub method: http::Method,
|
||||
pub path_params_schema: Option<serde_json::Value>,
|
||||
pub query_params_schema: Option<serde_json::Value>,
|
||||
pub body_schema: Option<serde_json::Value>,
|
||||
}}
|
||||
|
||||
{IMPORTS}
|
||||
{ENDPOINT_STRUCT}
|
||||
pub fn all_tools() -> Vec<EndpointTool> {{
|
||||
vec![
|
||||
{tool_definitions_str}
|
||||
@@ -274,7 +284,7 @@ def main():
|
||||
script_dir = Path(__file__).parent
|
||||
backend_dir = script_dir.parent
|
||||
openapi_file = backend_dir / "windmill-api" / "openapi.yaml"
|
||||
output_file = backend_dir / "windmill-api" / "src" / "mcp_tools.rs"
|
||||
output_file = backend_dir / "windmill-api" / "src" / "mcp" / "tools" / "auto_generated_endpoints.rs"
|
||||
|
||||
if not openapi_file.exists():
|
||||
print(f"OpenAPI file not found: {openapi_file}", file=sys.stderr)
|
||||
|
||||
1
backend/migrations/20250721160151_add_ruby.down.sql
Normal file
1
backend/migrations/20250721160151_add_ruby.down.sql
Normal file
@@ -0,0 +1 @@
|
||||
-- Add down migration script here
|
||||
3
backend/migrations/20250721160151_add_ruby.up.sql
Normal file
3
backend/migrations/20250721160151_add_ruby.up.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
-- Add up migration script here
|
||||
ALTER TYPE SCRIPT_LANG ADD VALUE IF NOT EXISTS 'ruby';
|
||||
UPDATE config set config = jsonb_set(config, '{worker_tags}', config->'worker_tags' || '["ruby"]'::jsonb) where name = 'worker__default' and config @> '{"worker_tags": ["deno", "python3", "go", "bash", "powershell", "dependency", "flow", "hub", "other", "bun", "php", "rust", "ansible", "csharp", "nu", "java", "duckdb"]}'::jsonb AND NOT config->'worker_tags' @> '"ruby"'::jsonb;
|
||||
@@ -0,0 +1,4 @@
|
||||
-- Remove auto-add columns for instance groups
|
||||
ALTER TABLE workspace_settings
|
||||
DROP COLUMN auto_add_instance_groups,
|
||||
DROP COLUMN auto_add_instance_groups_roles;
|
||||
@@ -0,0 +1,4 @@
|
||||
-- Add auto-add columns for instance groups
|
||||
ALTER TABLE workspace_settings
|
||||
ADD COLUMN auto_add_instance_groups text[] DEFAULT '{}',
|
||||
ADD COLUMN auto_add_instance_groups_roles jsonb DEFAULT '{}';
|
||||
@@ -0,0 +1,3 @@
|
||||
-- Remove added_via tracking
|
||||
DROP INDEX idx_usr_added_via;
|
||||
ALTER TABLE usr DROP COLUMN added_via;
|
||||
@@ -0,0 +1,8 @@
|
||||
-- Add added_via column to track how users were added to workspaces
|
||||
-- NULL = manual addition
|
||||
-- {"source": "domain", "domain": "company.com"} = domain auto-add
|
||||
-- {"source": "instance_group", "group": "developers", "role": "developer"} = instance group auto-add
|
||||
ALTER TABLE usr ADD COLUMN added_via jsonb DEFAULT NULL;
|
||||
|
||||
-- Add index for efficient queries on added_via
|
||||
CREATE INDEX idx_usr_added_via ON usr USING gin (added_via);
|
||||
@@ -0,0 +1 @@
|
||||
-- Add down migration script here
|
||||
@@ -0,0 +1,2 @@
|
||||
-- Add up migration script here
|
||||
ALTER TYPE JOB_KIND ADD VALUE IF NOT EXISTS 'aiagent';
|
||||
@@ -128,7 +128,7 @@ pub fn parse_python_signature(
|
||||
&& default.is_some()
|
||||
&& default != Some(json!(FUNCTION_CALL))
|
||||
{
|
||||
typ = json_to_typ(default.as_ref().unwrap());
|
||||
typ = json_to_typ(default.as_ref().unwrap(), false);
|
||||
}
|
||||
|
||||
// if the type is still a list of unknowns after checking the default, we set it to a list of strings to not break past behavior
|
||||
|
||||
19
backend/parsers/windmill-parser-ruby/Cargo.toml
Normal file
19
backend/parsers/windmill-parser-ruby/Cargo.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "windmill-parser-ruby"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
authors.workspace = true
|
||||
|
||||
[lib]
|
||||
name = "windmill_parser_ruby"
|
||||
path = "./src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
windmill-parser.workspace = true
|
||||
tree-sitter.workspace = true
|
||||
tree-sitter-ruby.workspace = true
|
||||
anyhow.workspace = true
|
||||
wasm-bindgen.workspace = true
|
||||
serde_json.workspace = true
|
||||
regex.workspace = true
|
||||
lazy_static.workspace = true
|
||||
410
backend/parsers/windmill-parser-ruby/src/lib.rs
Normal file
410
backend/parsers/windmill-parser-ruby/src/lib.rs
Normal file
@@ -0,0 +1,410 @@
|
||||
#![cfg_attr(target_arch = "wasm32", feature(c_variadic))]
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
pub mod wasm_libc;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use anyhow::bail;
|
||||
use regex::Regex;
|
||||
use serde_json::Value;
|
||||
use tree_sitter::Node;
|
||||
use tree_sitter::Range;
|
||||
use windmill_parser::json_to_typ;
|
||||
use windmill_parser::Arg;
|
||||
use windmill_parser::MainArgSignature;
|
||||
|
||||
pub fn parse_ruby_sig_meta(code: &str) -> anyhow::Result<MainArgSignature> {
|
||||
let mut parser = tree_sitter::Parser::new();
|
||||
let language = tree_sitter_ruby::LANGUAGE;
|
||||
parser
|
||||
.set_language(&language.into())
|
||||
.map_err(|e| anyhow!("Error setting Ruby as language: {e}"))?;
|
||||
|
||||
// Parse code
|
||||
let tree = parser
|
||||
.parse(code, None)
|
||||
.ok_or(anyhow!("Failed to parse code"))?;
|
||||
let root_node = tree.root_node();
|
||||
|
||||
root_node.clone().to_string();
|
||||
// Traverse the AST to find the Main method signature
|
||||
let args = find_main_signature(root_node, code)?;
|
||||
let no_main_func = Some(args.is_none());
|
||||
|
||||
let main_sig = MainArgSignature {
|
||||
star_args: false,
|
||||
star_kwargs: false,
|
||||
args: args.unwrap_or_default(),
|
||||
has_preprocessor: None,
|
||||
no_main_func,
|
||||
};
|
||||
|
||||
Ok(main_sig)
|
||||
}
|
||||
|
||||
pub fn parse_ruby_signature(code: &str) -> anyhow::Result<MainArgSignature> {
|
||||
Ok(parse_ruby_sig_meta(code)?)
|
||||
}
|
||||
|
||||
pub fn parse_ruby_requirements(code: &str) -> anyhow::Result<String> {
|
||||
let mut parser = tree_sitter::Parser::new();
|
||||
let language = tree_sitter_ruby::LANGUAGE;
|
||||
parser
|
||||
.set_language(&language.into())
|
||||
.map_err(|e| anyhow!("Error setting Ruby as language: {e}"))?;
|
||||
|
||||
// Parse code
|
||||
let tree = parser
|
||||
.parse(code, None)
|
||||
.ok_or(anyhow!("Failed to parse code"))?;
|
||||
let root_node = tree.root_node();
|
||||
|
||||
root_node.clone().to_string();
|
||||
let mut cursor = root_node.walk();
|
||||
'top_level: for x in root_node.children(&mut cursor) {
|
||||
if x.kind() == "call" {
|
||||
for (i, n) in x.children(&mut x.walk()).enumerate() {
|
||||
if i == 0
|
||||
&& n.kind() == "identifier"
|
||||
&& !n
|
||||
.utf8_text(code.as_bytes())
|
||||
.map(|ident| ident == "gemfile")
|
||||
.unwrap_or_default()
|
||||
{
|
||||
continue 'top_level;
|
||||
} else if n.kind() == "do_block" {
|
||||
let req = n.utf8_text(code.as_bytes())?.to_owned();
|
||||
|
||||
lazy_static::lazy_static! {
|
||||
static ref WINDMILL_RE: Regex = Regex::new(r"(?m)^\s*require\s*'windmill/inline'").unwrap();
|
||||
}
|
||||
|
||||
if WINDMILL_RE.find(&code).is_none() {
|
||||
return Err(anyhow!(
|
||||
"`require 'windmill/inline'` is not detected - please add `require 'windmill/inline'` in order to use inline gemfile.
|
||||
Your Gemfile syntax will be compatible with bundler/inline."
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
return req
|
||||
// gemfile do_block comes with 'do' and 'end'
|
||||
// we want to omit these by taking slice
|
||||
.get(2..(req.len() - 3))
|
||||
.map(str::to_owned)
|
||||
.ok_or(anyhow!("Invalid gemfile do block"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(String::new())
|
||||
}
|
||||
|
||||
// Function to find the Main method's signature
|
||||
fn find_main_signature<'a>(root_node: Node<'a>, code: &str) -> anyhow::Result<Option<Vec<Arg>>> {
|
||||
let mut cursor = root_node.walk();
|
||||
'top_level: for x in root_node.children(&mut cursor) {
|
||||
if x.kind() == "method" {
|
||||
let mut args = vec![];
|
||||
for (i, m) in x.children(&mut x.walk()).skip(1).enumerate() {
|
||||
if i == 0
|
||||
&& m.kind() == "identifier"
|
||||
&& !m
|
||||
.utf8_text(code.as_bytes())
|
||||
.map(|ident| ident == "main")
|
||||
.unwrap_or_default()
|
||||
{
|
||||
continue 'top_level;
|
||||
} else if m.kind() == "method_parameters" {
|
||||
for a in m.children(&mut m.walk()) {
|
||||
if a.kind() == "identifier" {
|
||||
a.utf8_text(code.as_bytes()).inspect(|name| {
|
||||
args.push(Arg { name: (*name).to_owned(), ..Default::default() })
|
||||
})?;
|
||||
}
|
||||
if a.kind() == "optional_parameter" {
|
||||
let mut walk = a.walk();
|
||||
let mut it = a.children(&mut walk).into_iter();
|
||||
match (it.next().and_then(|n| n.utf8_text(code.as_bytes()).ok()), {
|
||||
// Skip `=`
|
||||
it.next();
|
||||
it.next().map(|n| n.range())
|
||||
}) {
|
||||
(Some(ident), Some(Range { start_byte, end_byte, .. })) => {
|
||||
let unparsed =
|
||||
&code[start_byte..end_byte].replace("nil", "null");
|
||||
let default: Value = serde_json::from_str(unparsed).map_err(
|
||||
|e|
|
||||
anyhow!("Cannot convert default value to json\n\tvalue: {unparsed}\n\terror: {e}{}",
|
||||
if e.to_string().contains("key must be a string") {
|
||||
"\n\nNOTE: If you are trying to declare default hash, use following syntax:\n { \"<key>\": <value> }"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
))?;
|
||||
args.push(Arg {
|
||||
name: ident.to_owned(),
|
||||
typ: json_to_typ(&default, true),
|
||||
default: Some(default),
|
||||
has_default: true,
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
_ => {
|
||||
let Range { start_byte, end_byte, .. } = a.range();
|
||||
bail!(
|
||||
"Cannot parse optional parameter: {}",
|
||||
&code.get(start_byte..end_byte).unwrap_or("CANNOT DISPLAY")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
let kind = a.kind();
|
||||
if matches!(
|
||||
kind,
|
||||
"keyword_parameter" | "splat_parameter" | "hash_splat_parameter"
|
||||
) {
|
||||
let Range { start_byte, end_byte, .. } = a.range();
|
||||
bail!(
|
||||
" - {}\n{}s are not supported",
|
||||
&code.get(start_byte..end_byte).unwrap_or("CANNOT DISPLAY"),
|
||||
kind.replace("_", " ")
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ok(Some(args));
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
|
||||
use serde_json::json;
|
||||
use windmill_parser::{ObjectProperty, ObjectType, Typ};
|
||||
|
||||
use super::parse_ruby_sig_meta as parse;
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_parse_ruby_no_main() {
|
||||
let code = r#"
|
||||
def not_main end
|
||||
def private_fn end
|
||||
"#;
|
||||
let sig = parse(code).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
sig,
|
||||
MainArgSignature { no_main_func: Some(true), ..Default::default() }
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_parse_ruby_no_args() {
|
||||
let code = r#"
|
||||
def main
|
||||
end
|
||||
"#;
|
||||
let sig = parse(code).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
sig,
|
||||
MainArgSignature { no_main_func: Some(false), ..Default::default() }
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_parse_ruby_positional_args() {
|
||||
let sig = {
|
||||
let code = r#"def main(a, b, c) end"#;
|
||||
parse(code).unwrap()
|
||||
};
|
||||
let sig2 = {
|
||||
let code = r#"
|
||||
def main a, b, c
|
||||
end"#;
|
||||
parse(code).unwrap()
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
sig,
|
||||
MainArgSignature {
|
||||
args: vec![
|
||||
Arg { name: "a".into(), ..Default::default() },
|
||||
Arg { name: "b".into(), ..Default::default() },
|
||||
Arg { name: "c".into(), ..Default::default() }
|
||||
],
|
||||
no_main_func: Some(false),
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
assert_eq!(sig2, sig);
|
||||
}
|
||||
#[test]
|
||||
fn test_parse_ruby_lists() {
|
||||
let sig = {
|
||||
let code = r#"def main(a = [ 1, 2, 3 ], b = [ 1, false, nil, "test"]) end"#;
|
||||
parse(code).unwrap()
|
||||
};
|
||||
assert_eq!(
|
||||
sig,
|
||||
MainArgSignature {
|
||||
args: vec![
|
||||
Arg {
|
||||
name: "a".into(),
|
||||
has_default: true,
|
||||
typ: Typ::List(Box::new(Typ::Int)),
|
||||
default: Some(json!([1, 2, 3])),
|
||||
..Default::default()
|
||||
},
|
||||
Arg {
|
||||
name: "b".into(),
|
||||
has_default: true,
|
||||
typ: Typ::List(Box::new(Typ::Unknown)),
|
||||
default: Some(json!([1, false, null, "test"])),
|
||||
..Default::default()
|
||||
},
|
||||
],
|
||||
no_main_func: Some(false),
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_parse_ruby_hashes() {
|
||||
let sig = {
|
||||
let code = r#"def main(a = { "1": 4, "2": [ 1, 2, 3] }) end"#;
|
||||
parse(code).unwrap()
|
||||
};
|
||||
assert_eq!(
|
||||
sig,
|
||||
MainArgSignature {
|
||||
args: vec![Arg {
|
||||
name: "a".into(),
|
||||
has_default: true,
|
||||
typ: Typ::Object(ObjectType::new(
|
||||
None,
|
||||
Some(vec![
|
||||
ObjectProperty { key: "1".into(), typ: Box::new(Typ::Int) },
|
||||
ObjectProperty {
|
||||
key: "2".into(),
|
||||
typ: Box::new(Typ::List(Box::new(Typ::Int)))
|
||||
}
|
||||
],)
|
||||
)),
|
||||
default: Some(json!({"1": 4, "2": [ 1, 2, 3 ]})),
|
||||
..Default::default()
|
||||
},],
|
||||
no_main_func: Some(false),
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
}
|
||||
#[test]
|
||||
fn test_parse_ruby_default_args() {
|
||||
let sig = {
|
||||
let code =
|
||||
r#"def main(a = 10, b = "hey", c = false, d = [ 1, 2, 3 ], e = { "a": 43 }) end"#;
|
||||
parse(code).unwrap()
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
sig,
|
||||
MainArgSignature {
|
||||
args: vec![
|
||||
Arg {
|
||||
name: "a".into(),
|
||||
has_default: true,
|
||||
typ: Typ::Int,
|
||||
default: Some(json!(10)),
|
||||
..Default::default()
|
||||
},
|
||||
Arg {
|
||||
name: "b".into(),
|
||||
has_default: true,
|
||||
typ: Typ::Str(None),
|
||||
default: Some(json!("hey")),
|
||||
..Default::default()
|
||||
},
|
||||
Arg {
|
||||
name: "c".into(),
|
||||
has_default: true,
|
||||
typ: Typ::Bool,
|
||||
default: Some(json!(false)),
|
||||
..Default::default()
|
||||
},
|
||||
Arg {
|
||||
name: "d".into(),
|
||||
has_default: true,
|
||||
typ: Typ::List(Box::new(Typ::Int)),
|
||||
default: Some(json!([1, 2, 3])),
|
||||
..Default::default()
|
||||
},
|
||||
Arg {
|
||||
name: "e".into(),
|
||||
has_default: true,
|
||||
typ: Typ::Object(ObjectType::new(
|
||||
None,
|
||||
Some(vec![ObjectProperty {
|
||||
key: "a".into(),
|
||||
typ: Box::new(Typ::Int)
|
||||
}])
|
||||
)),
|
||||
default: Some(json!({"a": 43})),
|
||||
..Default::default()
|
||||
},
|
||||
],
|
||||
no_main_func: Some(false),
|
||||
..Default::default()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_ruby_unsupported() {
|
||||
assert_eq!(
|
||||
&parse("def main( a: ) end").unwrap_err().to_string(),
|
||||
" - a:\nkeyword parameters are not supported"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
&parse("def main( *a ) end").unwrap_err().to_string(),
|
||||
" - *a\nsplat parameters are not supported"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
&parse("def main( **a ) end").unwrap_err().to_string(),
|
||||
" - **a\nhash splat parameters are not supported"
|
||||
);
|
||||
|
||||
assert!(&parse("def main( a = Time.now ) end").is_err());
|
||||
assert!(&parse("def main( a = :symbol ) end").is_err());
|
||||
assert!(&parse("def main( a = { b: 2 } ) end").is_err());
|
||||
assert!(&parse("def main( a = { b => 2 } ) end").is_err());
|
||||
assert!(&parse(r#"def main( a = { "b" => 2 } ) end"#).is_err());
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn test_parse_ruby_requirements() {
|
||||
// assert_eq!(
|
||||
// parse_ruby_requirements(
|
||||
// "
|
||||
// require 'dep1'
|
||||
// require 'dep2'
|
||||
// require 'dep2/submod'
|
||||
// require 'u/username/script'
|
||||
// require 'f/folder/script'
|
||||
// "
|
||||
// )
|
||||
// .unwrap(),
|
||||
// vec![
|
||||
// "dep1".to_owned(),
|
||||
// "dep2".into(),
|
||||
// "dep2".into(),
|
||||
// "u/username/script".into(),
|
||||
// "f/folder/script".into(),
|
||||
// ]
|
||||
// );
|
||||
// }
|
||||
}
|
||||
297
backend/parsers/windmill-parser-ruby/src/wasm_libc.rs
Normal file
297
backend/parsers/windmill-parser-ruby/src/wasm_libc.rs
Normal file
@@ -0,0 +1,297 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::{Mutex, OnceLock};
|
||||
use std::{
|
||||
alloc::{self, Layout},
|
||||
ffi::{c_char, c_int, c_void},
|
||||
mem::align_of,
|
||||
ptr,
|
||||
};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
/* -------------------------------- stdlib.h -------------------------------- */
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn abort() {
|
||||
panic!("Aborted from C");
|
||||
}
|
||||
|
||||
macro_rules! console_log {
|
||||
($($t:tt)*) => (unsafe { log(&format_args!($($t)*).to_string()) })
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
extern "C" {
|
||||
#[wasm_bindgen(js_namespace = console)]
|
||||
fn log(a: &str);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn malloc(size: usize) -> *mut c_void {
|
||||
if size == 0 {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
|
||||
let (layout, offset_to_data) = layout_for_size_prepended(size);
|
||||
let buf = alloc::alloc(layout);
|
||||
store_layout(buf, layout, offset_to_data)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn calloc(count: usize, size: usize) -> *mut c_void {
|
||||
if count == 0 || size == 0 {
|
||||
return ptr::null_mut();
|
||||
}
|
||||
|
||||
let (layout, offset_to_data) = layout_for_size_prepended(size * count);
|
||||
let buf = alloc::alloc_zeroed(layout);
|
||||
store_layout(buf, layout, offset_to_data)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn realloc(buf: *mut c_void, new_size: usize) -> *mut c_void {
|
||||
if buf.is_null() {
|
||||
malloc(new_size)
|
||||
} else if new_size == 0 {
|
||||
free(buf);
|
||||
ptr::null_mut()
|
||||
} else {
|
||||
let (old_buf, old_layout) = retrieve_layout(buf);
|
||||
let (new_layout, offset_to_data) = layout_for_size_prepended(new_size);
|
||||
let new_buf = alloc::realloc(old_buf, old_layout, new_layout.size());
|
||||
store_layout(new_buf, new_layout, offset_to_data)
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn free(buf: *mut c_void) {
|
||||
if buf.is_null() {
|
||||
return;
|
||||
}
|
||||
let (buf, layout) = retrieve_layout(buf);
|
||||
alloc::dealloc(buf, layout);
|
||||
}
|
||||
|
||||
// In all these allocations, we store the layout before the data for later retrieval.
|
||||
// This is because we need to know the layout when deallocating the memory.
|
||||
// Here are some helper methods for that:
|
||||
|
||||
/// Given a pointer to the data, retrieve the layout and the pointer to the layout.
|
||||
unsafe fn retrieve_layout(buf: *mut c_void) -> (*mut u8, Layout) {
|
||||
let (_, layout_offset) = Layout::new::<Layout>()
|
||||
.extend(Layout::from_size_align(0, align_of::<*const u8>() * 2).unwrap())
|
||||
.unwrap();
|
||||
|
||||
let buf = (buf as *mut u8).offset(-(layout_offset as isize));
|
||||
let layout = *(buf as *mut Layout);
|
||||
|
||||
(buf, layout)
|
||||
}
|
||||
|
||||
/// Calculate a layout for a given size with space for storing a layout at the start.
|
||||
/// Returns the layout and the offset to the data.
|
||||
fn layout_for_size_prepended(size: usize) -> (Layout, usize) {
|
||||
Layout::new::<Layout>()
|
||||
.extend(Layout::from_size_align(size, align_of::<*const u8>() * 2).unwrap())
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Store a layout in the pointer, returning a pointer to where the data should be stored.
|
||||
unsafe fn store_layout(buf: *mut u8, layout: Layout, offset_to_data: usize) -> *mut c_void {
|
||||
*(buf as *mut Layout) = layout;
|
||||
(buf as *mut u8).offset(offset_to_data as isize) as *mut c_void
|
||||
}
|
||||
|
||||
/* -------------------------------- string.h -------------------------------- */
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strncmp(ptr1: *const c_void, ptr2: *const c_void, n: usize) -> c_int {
|
||||
let s1 = std::slice::from_raw_parts(ptr1 as *const u8, n);
|
||||
let s2 = std::slice::from_raw_parts(ptr2 as *const u8, n);
|
||||
|
||||
for (a, b) in s1.iter().zip(s2.iter()) {
|
||||
if *a != *b || *a == 0 {
|
||||
return (*a as i32) - (*b as i32);
|
||||
}
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
// Implementation by AI:
|
||||
pub type size_t = usize;
|
||||
use std::slice;
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn memchr(
|
||||
haystack: *const c_void,
|
||||
needle: c_int,
|
||||
len: usize,
|
||||
) -> *mut c_void {
|
||||
if haystack.is_null() || len == 0 {
|
||||
return ptr::null_mut(); // Return null if the input pointer is null or length is zero
|
||||
}
|
||||
|
||||
let needle_byte = needle as u8; // Convert needle to a byte
|
||||
|
||||
// Create a pointer to the start of the haystack
|
||||
let mut current = haystack as *const u8;
|
||||
|
||||
// Iterate through the memory block
|
||||
for _ in 0..len {
|
||||
if *current == needle_byte {
|
||||
return current as *mut c_void; // Return the pointer to the found byte
|
||||
}
|
||||
current = current.add(1); // Move to the next byte
|
||||
}
|
||||
|
||||
ptr::null_mut() // Return null if the byte was not found
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn strchr(mut s: *const c_char, c: c_int) -> *mut c_char {
|
||||
if s.is_null() {
|
||||
return std::ptr::null_mut(); // Return null if the input string is null
|
||||
}
|
||||
|
||||
let target = c as u8 as char; // Convert c to a char
|
||||
let mut current = s;
|
||||
|
||||
// Iterate through the string until we find the character or reach the end
|
||||
while *current != 0 {
|
||||
if *current as u8 as char == target {
|
||||
return current as *mut c_char; // Return the pointer to the found character
|
||||
}
|
||||
current = current.add(1); // Move to the next character
|
||||
}
|
||||
|
||||
std::ptr::null_mut() // Return null if the character was not found
|
||||
}
|
||||
// End of AI implemetation
|
||||
/* -------------------------------- wctype.h -------------------------------- */
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn iswspace(c: c_int) -> bool {
|
||||
char::from_u32(c as u32).map_or(false, |c| c.is_whitespace())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn iswalnum(c: c_int) -> bool {
|
||||
char::from_u32(c as u32).map_or(false, |c| c.is_alphanumeric())
|
||||
}
|
||||
|
||||
// Implementation by AI:
|
||||
pub type wint_t = u32;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn iswdigit(wc: wint_t) -> c_int {
|
||||
// Check if the character is a digit ('0' to '9')
|
||||
if wc >= '0' as wint_t && wc <= '9' as wint_t {
|
||||
return 1; // Return true (1)
|
||||
}
|
||||
0 // Return false (0)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn iswupper(wc: wint_t) -> c_int {
|
||||
// Check if the character is an uppercase letter ('A' to 'Z')
|
||||
if wc >= 'A' as wint_t && wc <= 'Z' as wint_t {
|
||||
return 1; // Return true (1)
|
||||
}
|
||||
0 // Return false (0)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn iswalpha(wc: wint_t) -> c_int {
|
||||
// Check if the character is an alphabetic character ('A' to 'Z' or 'a' to 'z')
|
||||
if (wc >= 'A' as wint_t && wc <= 'Z' as wint_t) || (wc >= 'a' as wint_t && wc <= 'z' as wint_t) {
|
||||
return 1; // Return true (1)
|
||||
}
|
||||
0 // Return false (0)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn iswlower(wc: wint_t) -> c_int {
|
||||
// Check if the character is a lowercase letter ('a' to 'z')
|
||||
if wc >= 'a' as wint_t && wc <= 'z' as wint_t {
|
||||
return 1; // Return true (1)
|
||||
}
|
||||
0 // Return false (0)
|
||||
}
|
||||
// End of AI implemetation
|
||||
|
||||
|
||||
/* --------------------------------- time.h --------------------------------- */
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn clock() -> u64 {
|
||||
panic!("clock is not supported");
|
||||
}
|
||||
|
||||
/* --------------------------------- ctype.h -------------------------------- */
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn isprint(c: c_int) -> bool {
|
||||
c >= 32 && c <= 126
|
||||
}
|
||||
|
||||
/* --------------------------------- stdio.h -------------------------------- */
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn fprintf(_file: *mut c_void, _format: *const c_void, _args: ...) -> c_int {
|
||||
panic!("fprintf is not supported");
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn fputs(_s: *const c_void, _file: *mut c_void) -> c_int {
|
||||
panic!("fputs is not supported");
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn fputc(_c: c_int, _file: *mut c_void) -> c_int {
|
||||
panic!("fputc is not supported");
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn fdopen(_fd: c_int, _mode: *const c_void) -> *mut c_void {
|
||||
panic!("fdopen is not supported");
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn fclose(_file: *mut c_void) -> c_int {
|
||||
panic!("fclose is not supported");
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn fwrite(
|
||||
_ptr: *const c_void,
|
||||
_size: usize,
|
||||
_nmemb: usize,
|
||||
_stream: *mut c_void,
|
||||
) -> usize {
|
||||
panic!("fwrite is not supported");
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn vsnprintf(
|
||||
_buf: *mut c_char,
|
||||
_size: usize,
|
||||
_format: *const c_char,
|
||||
_args: ...
|
||||
) -> c_int {
|
||||
panic!("vsnprintf is not supported");
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn clock_gettime(ptr: usize, new_size: usize) {
|
||||
panic!("clock_gettime is not supported");
|
||||
}
|
||||
|
||||
// int snprintf( char* restrict buffer, size_t bufsz, const char* restrict format, ... );
|
||||
#[no_mangle]
|
||||
pub extern "C" fn snprintf() {
|
||||
panic!("snprintf is not supported");
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn __assert_fail(_: *const i32, _: *const i32, _: *const i32, _: *const i32) {
|
||||
panic!("oh no");
|
||||
}
|
||||
@@ -388,7 +388,7 @@ fn parse_param(
|
||||
};
|
||||
|
||||
if typ == Typ::Unknown && dflt.is_some() {
|
||||
typ = json_to_typ(dflt.as_ref().unwrap());
|
||||
typ = json_to_typ(dflt.as_ref().unwrap(), false);
|
||||
}
|
||||
Ok(Arg { otyp: None, name, typ, default: dflt, has_default: true, oidx: None })
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ ansible-parser = [ "dep:windmill-parser-yaml"]
|
||||
csharp-parser = [ "dep:windmill-parser-csharp"]
|
||||
nu-parser = [ "dep:windmill-parser-nu"]
|
||||
java-parser = [ "dep:windmill-parser-java"]
|
||||
ruby-parser = [ "dep:windmill-parser-ruby"]
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
@@ -45,6 +46,7 @@ windmill-parser-yaml = { workspace = true, optional = true }
|
||||
windmill-parser-csharp = { workspace = true, optional = true }
|
||||
windmill-parser-nu = { workspace = true, optional = true }
|
||||
windmill-parser-java = { workspace = true, optional = true }
|
||||
windmill-parser-ruby = { workspace = true, optional = true }
|
||||
wasm-bindgen.workspace = true
|
||||
serde_json.workspace = true
|
||||
getrandom = { workspace = true, features = ["js"] }
|
||||
|
||||
@@ -50,11 +50,11 @@ const targets = [
|
||||
desc: "Java",
|
||||
features: "java-parser",
|
||||
env: "tree-sitter",
|
||||
# }, {
|
||||
# ident: "ruby",
|
||||
# desc: "Ruby",
|
||||
# features: "ruby-parser",
|
||||
# env: "tree-sitter",
|
||||
}, {
|
||||
ident: "ruby",
|
||||
desc: "Ruby",
|
||||
features: "ruby-parser",
|
||||
env: "tree-sitter",
|
||||
},
|
||||
# ^^^ Add new entry here ^^^
|
||||
];
|
||||
@@ -130,3 +130,4 @@ def main [
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -168,6 +168,11 @@ pub fn parse_java(code: &str) -> String {
|
||||
wrap_sig(windmill_parser_java::parse_java_signature(code))
|
||||
}
|
||||
|
||||
#[cfg(feature = "ruby-parser")]
|
||||
#[wasm_bindgen]
|
||||
pub fn parse_ruby(code: &str) -> String {
|
||||
wrap_sig(windmill_parser_ruby::parse_ruby_signature(code))
|
||||
}
|
||||
#[cfg(feature = "sql-parser")]
|
||||
#[wasm_bindgen]
|
||||
pub fn parse_assets_sql(code: &str) -> String {
|
||||
|
||||
@@ -5,3 +5,7 @@ void *memmove(void *dest, const void *src, unsigned long n);
|
||||
void *memset(void *s, int c, unsigned long n);
|
||||
int memcmp(const void *ptr1, const void *ptr2, unsigned long n);
|
||||
int strncmp(const char *s1, const char *s2, unsigned long n);
|
||||
|
||||
// Manually added (needed for Ruby)
|
||||
void *memchr (void *s, int c, size_t n);
|
||||
char *strchr (char *s, int c);
|
||||
|
||||
@@ -5,3 +5,9 @@ typedef __WINT_TYPE__ wint_t;
|
||||
|
||||
int iswspace(wchar_t ch);
|
||||
int iswalnum(wint_t _wc);
|
||||
|
||||
// Manually added (needed for Ruby)
|
||||
int iswdigit(wint_t _wc);
|
||||
int iswupper(wint_t _wc);
|
||||
int iswalpha(wint_t _wc);
|
||||
int iswlower(wint_t _wc);
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
* LICENSE-AGPL for a copy of the license.
|
||||
*/
|
||||
|
||||
use std::mem::discriminant;
|
||||
|
||||
use convert_case::{Boundary, Case, Casing};
|
||||
use serde::Serialize;
|
||||
use serde_json::Value;
|
||||
@@ -53,7 +55,7 @@ pub struct OneOfVariant {
|
||||
pub properties: Vec<ObjectProperty>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone, Debug, PartialEq)]
|
||||
#[derive(Serialize, Clone, Debug, PartialEq, Default)]
|
||||
#[serde(rename_all(serialize = "lowercase"))]
|
||||
pub enum Typ {
|
||||
Str(Option<Vec<String>>),
|
||||
@@ -69,10 +71,11 @@ pub enum Typ {
|
||||
DynSelect(String),
|
||||
Object(ObjectType),
|
||||
OneOf(Vec<OneOfVariant>),
|
||||
#[default]
|
||||
Unknown,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Clone, Debug, PartialEq)]
|
||||
#[derive(Serialize, Clone, Debug, PartialEq, Default)]
|
||||
pub struct Arg {
|
||||
pub name: String,
|
||||
pub otyp: Option<String>,
|
||||
@@ -82,7 +85,7 @@ pub struct Arg {
|
||||
pub oidx: Option<i32>,
|
||||
}
|
||||
|
||||
pub fn json_to_typ(js: &Value) -> Typ {
|
||||
pub fn json_to_typ(js: &Value, precise_arrays: bool) -> Typ {
|
||||
match js {
|
||||
Value::String(_) => Typ::Str(None),
|
||||
Value::Number(n) if n.is_i64() => Typ::Int,
|
||||
@@ -92,11 +95,28 @@ pub fn json_to_typ(js: &Value) -> Typ {
|
||||
None,
|
||||
Some(
|
||||
o.iter()
|
||||
.map(|(k, v)| ObjectProperty { key: k.to_string(), typ: Box::new(json_to_typ(v)) })
|
||||
.map(|(k, v)| ObjectProperty {
|
||||
key: k.to_string(),
|
||||
typ: Box::new(json_to_typ(v, precise_arrays)),
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
)),
|
||||
Value::Array(a) => Typ::List(Box::new(a.first().map(json_to_typ).unwrap_or(Typ::Unknown))),
|
||||
Value::Array(a) => Typ::List(Box::new({
|
||||
// Check if all variant types are the same
|
||||
if !precise_arrays
|
||||
|| a.windows(2).all(|pair| {
|
||||
let (l, r) = (&pair[0], &pair[1]);
|
||||
discriminant(l) == discriminant(r)
|
||||
})
|
||||
{
|
||||
a.first()
|
||||
.map(|js| json_to_typ(js, precise_arrays))
|
||||
.unwrap_or(Typ::Unknown)
|
||||
} else {
|
||||
Typ::Unknown
|
||||
}
|
||||
})),
|
||||
_ => Typ::Unknown,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ use monitor::{
|
||||
load_base_url, load_otel, reload_critical_alerts_on_db_oversize,
|
||||
reload_delete_logs_periodically_setting, reload_indexer_config,
|
||||
reload_instance_python_version_setting, reload_maven_repos_setting,
|
||||
reload_no_default_maven_setting, reload_nuget_config_setting,
|
||||
reload_no_default_maven_setting, reload_nuget_config_setting, reload_ruby_repos_setting,
|
||||
reload_timeout_wait_result_setting, send_current_log_file_to_object_store,
|
||||
send_logs_to_object_store, WORKERS_NAMES,
|
||||
};
|
||||
@@ -47,7 +47,7 @@ use windmill_common::{
|
||||
NO_DEFAULT_MAVEN_SETTING, NPM_CONFIG_REGISTRY_SETTING, NUGET_CONFIG_SETTING, OAUTH_SETTING,
|
||||
OTEL_SETTING, PIP_INDEX_URL_SETTING, REQUEST_SIZE_LIMIT_SETTING,
|
||||
REQUIRE_PREEXISTING_USER_FOR_OAUTH_SETTING, RETENTION_PERIOD_SECS_SETTING,
|
||||
SAML_METADATA_SETTING, SCIM_TOKEN_SETTING, SMTP_SETTING, TEAMS_SETTING,
|
||||
RUBY_REPOS_SETTING, SAML_METADATA_SETTING, SCIM_TOKEN_SETTING, SMTP_SETTING, TEAMS_SETTING,
|
||||
TIMEOUT_WAIT_RESULT_SETTING,
|
||||
},
|
||||
scripts::ScriptLang,
|
||||
@@ -83,7 +83,8 @@ use windmill_worker::{
|
||||
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,
|
||||
JAVA_CACHE_DIR, NU_CACHE_DIR, POWERSHELL_CACHE_DIR, PY310_CACHE_DIR, PY311_CACHE_DIR,
|
||||
PY312_CACHE_DIR, PY313_CACHE_DIR, RUST_CACHE_DIR, TAR_JAVA_CACHE_DIR, UV_CACHE_DIR,
|
||||
PY312_CACHE_DIR, PY313_CACHE_DIR, RUBY_CACHE_DIR, RUST_CACHE_DIR, TAR_JAVA_CACHE_DIR,
|
||||
UV_CACHE_DIR,
|
||||
};
|
||||
|
||||
use crate::monitor::{
|
||||
@@ -1014,6 +1015,9 @@ Windmill Community Edition {GIT_VERSION}
|
||||
NO_DEFAULT_MAVEN_SETTING => {
|
||||
reload_no_default_maven_setting(&conn).await
|
||||
},
|
||||
RUBY_REPOS_SETTING => {
|
||||
reload_ruby_repos_setting(&conn).await
|
||||
},
|
||||
KEEP_JOB_DIR_SETTING => {
|
||||
load_keep_job_dir(&conn).await;
|
||||
},
|
||||
@@ -1368,6 +1372,7 @@ pub async fn run_workers(
|
||||
HUB_CACHE_DIR,
|
||||
POWERSHELL_CACHE_DIR,
|
||||
JAVA_CACHE_DIR,
|
||||
RUBY_CACHE_DIR,
|
||||
TAR_JAVA_CACHE_DIR, // for related places search: ADD_NEW_LANG
|
||||
] {
|
||||
DirBuilder::new()
|
||||
|
||||
@@ -11,13 +11,14 @@ use std::{
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use chrono::{NaiveDateTime, Utc};
|
||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||
use futures::{stream::FuturesUnordered, StreamExt};
|
||||
use serde::{de::DeserializeOwned, Deserialize};
|
||||
use sqlx::{Pool, Postgres};
|
||||
use tokio::{
|
||||
join,
|
||||
sync::{mpsc, RwLock},
|
||||
time::timeout,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
@@ -113,6 +114,12 @@ lazy_static::lazy_static! {
|
||||
&["tag"]
|
||||
).unwrap();
|
||||
|
||||
static ref QUEUE_RUNNING_COUNT: prometheus::IntGaugeVec = prometheus::register_int_gauge_vec!(
|
||||
"queue_running_count",
|
||||
"Number of running jobs in the queue",
|
||||
&["tag"]
|
||||
).unwrap();
|
||||
|
||||
}
|
||||
lazy_static::lazy_static! {
|
||||
static ref ZOMBIE_JOB_TIMEOUT: String = std::env::var("ZOMBIE_JOB_TIMEOUT")
|
||||
@@ -139,8 +146,12 @@ lazy_static::lazy_static! {
|
||||
pub static ref WORKERS_NAMES: Arc<RwLock<Vec<String>>> = Arc::new(RwLock::new(Vec::new()));
|
||||
|
||||
static ref QUEUE_COUNT_TAGS: Arc<RwLock<Vec<String>>> = Arc::new(RwLock::new(Vec::new()));
|
||||
static ref QUEUE_RUNNING_COUNT_TAGS: Arc<RwLock<Vec<String>>> = Arc::new(RwLock::new(Vec::new()));
|
||||
static ref DISABLE_CONCURRENCY_LIMIT: bool = std::env::var("DISABLE_CONCURRENCY_LIMIT").is_ok_and(|s| s == "true");
|
||||
|
||||
static ref STALE_JOB_TRESHOLD_MINUTES: Option<u64> = std::env::var("STALE_JOB_TRESHOLD_MINUTES")
|
||||
.ok()
|
||||
.and_then(|x| x.parse::<u64>().ok());
|
||||
}
|
||||
|
||||
pub async fn initial_load(
|
||||
@@ -287,6 +298,7 @@ pub async fn initial_load(
|
||||
reload_nuget_config_setting(&conn).await;
|
||||
reload_maven_repos_setting(&conn).await;
|
||||
reload_no_default_maven_setting(&conn).await;
|
||||
reload_ruby_repos_setting(&conn).await;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -681,20 +693,25 @@ async fn send_log_file_to_object_store(
|
||||
let (ok_lines, err_lines) = read_log_counters(ts_str);
|
||||
|
||||
if let Some(db) = conn.as_sql() {
|
||||
if let Err(e) = sqlx::query!("INSERT INTO log_file (hostname, mode, worker_group, log_ts, file_path, ok_lines, err_lines, json_fmt)
|
||||
match timeout(Duration::from_secs(10), sqlx::query!("INSERT INTO log_file (hostname, mode, worker_group, log_ts, file_path, ok_lines, err_lines, json_fmt)
|
||||
VALUES ($1, $2::text::LOG_MODE, $3, $4, $5, $6, $7, $8)
|
||||
ON CONFLICT (hostname, log_ts) DO UPDATE SET ok_lines = log_file.ok_lines + $6, err_lines = log_file.err_lines + $7",
|
||||
hostname, mode.to_string(), worker_group.clone(), ts, highest_file, ok_lines as i64, err_lines as i64, *JSON_FMT)
|
||||
.execute(db)
|
||||
.await {
|
||||
tracing::error!("Error inserting log file: {:?}", e);
|
||||
} else {
|
||||
if let Err(e) = LAST_LOG_FILE_SENT.lock().map(|mut last_log_file_sent| {
|
||||
last_log_file_sent.replace(ts);
|
||||
}) {
|
||||
tracing::error!("Error updating last log file sent: {:?}", e);
|
||||
.execute(db)).await {
|
||||
Ok(Ok(_)) => {
|
||||
if let Err(e) = LAST_LOG_FILE_SENT.lock().map(|mut last_log_file_sent| {
|
||||
last_log_file_sent.replace(ts);
|
||||
}) {
|
||||
tracing::error!("Error updating last log file sent: {:?}", e);
|
||||
}
|
||||
tracing::info!("Log file sent: {}", highest_file);
|
||||
}
|
||||
Ok(Err(e)) => {
|
||||
tracing::error!("Error inserting log file: {:?}", e);
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Error inserting log file, timeout elapsed: {:?}", e);
|
||||
}
|
||||
tracing::info!("Log file sent: {}", highest_file);
|
||||
}
|
||||
} else {
|
||||
// tracing::warn!("Not sending log file to object store in agent mode");
|
||||
@@ -1084,6 +1101,7 @@ pub async fn reload_nuget_config_setting(conn: &Connection) {
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn reload_maven_repos_setting(conn: &Connection) {
|
||||
reload_option_setting_with_tracing(
|
||||
conn,
|
||||
@@ -1093,6 +1111,7 @@ pub async fn reload_maven_repos_setting(conn: &Connection) {
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn reload_no_default_maven_setting(conn: &Connection) {
|
||||
let value = load_value_from_global_settings_with_conn(
|
||||
conn,
|
||||
@@ -1109,6 +1128,16 @@ pub async fn reload_no_default_maven_setting(conn: &Connection) {
|
||||
};
|
||||
}
|
||||
|
||||
pub async fn reload_ruby_repos_setting(conn: &Connection) {
|
||||
reload_url_list_setting_with_tracing(
|
||||
conn,
|
||||
windmill_common::global_settings::RUBY_REPOS_SETTING,
|
||||
"RUBY_REPOS",
|
||||
windmill_worker::RUBY_REPOS.clone(),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
pub async fn reload_retention_period_setting(conn: &Connection) {
|
||||
if let Err(e) = reload_setting(
|
||||
conn,
|
||||
@@ -1278,6 +1307,100 @@ pub async fn reload_option_setting<T: FromStr + DeserializeOwned>(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn reload_url_list_setting_with_tracing(
|
||||
conn: &Connection,
|
||||
setting_name: &str,
|
||||
std_env_var: &str,
|
||||
lock: Arc<RwLock<Option<Vec<url::Url>>>>,
|
||||
) {
|
||||
if let Err(e) = reload_url_list_setting(conn, setting_name, std_env_var, lock.clone()).await {
|
||||
tracing::error!("Error reloading setting {}: {:?}", setting_name, e)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn reload_url_list_setting(
|
||||
conn: &Connection,
|
||||
setting_name: &str,
|
||||
std_env_var: &str,
|
||||
lock: Arc<RwLock<Option<Vec<url::Url>>>>,
|
||||
) -> error::Result<()> {
|
||||
// Check for force environment variable
|
||||
if let Ok(force_value) = std::env::var(format!("FORCE_{}", std_env_var)) {
|
||||
let mut urls = Vec::new();
|
||||
for url_str in force_value.trim().split_whitespace() {
|
||||
match url::Url::parse(url_str) {
|
||||
Ok(url) => urls.push(url),
|
||||
Err(e) => {
|
||||
return Err(error::Error::BadRequest(format!(
|
||||
"Invalid URL in FORCE_{}: '{}': {}",
|
||||
std_env_var, url_str, e
|
||||
)));
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut l = lock.write().await;
|
||||
*l = if urls.is_empty() { None } else { Some(urls) };
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let q = load_value_from_global_settings_with_conn(conn, setting_name, true).await?;
|
||||
|
||||
// Check regular environment variable
|
||||
let mut value = if let Ok(env_value) = std::env::var(std_env_var) {
|
||||
let mut urls = Vec::new();
|
||||
for url_str in env_value.trim().split_whitespace() {
|
||||
match url::Url::parse(url_str) {
|
||||
Ok(url) => urls.push(url),
|
||||
Err(_) => {
|
||||
// Log error but continue, similar to force variable handling
|
||||
tracing::error!("Invalid URL in {}: '{}'", std_env_var, url_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
if urls.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(urls)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Check database setting
|
||||
if let Some(q) = q {
|
||||
if let Ok(repos_str) = serde_json::from_value::<String>(q.clone()) {
|
||||
let mut urls = Vec::new();
|
||||
for url_str in repos_str.trim().split_whitespace() {
|
||||
match url::Url::parse(url_str) {
|
||||
Ok(url) => urls.push(url),
|
||||
Err(e) => {
|
||||
tracing::error!("Invalid URL in {}: '{}': {}", setting_name, url_str, e);
|
||||
// Continue with other URLs, just skip invalid ones
|
||||
}
|
||||
}
|
||||
}
|
||||
tracing::info!(
|
||||
"Loaded setting {} from db config: {} URLs",
|
||||
setting_name,
|
||||
urls.len()
|
||||
);
|
||||
value = if urls.is_empty() { None } else { Some(urls) };
|
||||
} else {
|
||||
tracing::error!("Could not parse {} found: {:#?}", setting_name, &q);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if value.is_none() {
|
||||
tracing::info!("Loaded {} setting to None", setting_name);
|
||||
}
|
||||
let mut l = lock.write().await;
|
||||
*l = value;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn reload_setting<T: FromStr + DeserializeOwned + Display>(
|
||||
conn: &Connection,
|
||||
setting_name: &str,
|
||||
@@ -1377,6 +1500,14 @@ pub async fn monitor_db(
|
||||
}
|
||||
};
|
||||
|
||||
let stale_jobs_f = async {
|
||||
if server_mode && !initial_load {
|
||||
if let Some(db) = conn.as_sql() {
|
||||
stale_job_cancellation(&db).await;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// run every 5 minutes
|
||||
let cleanup_concurrency_counters_f = async {
|
||||
if server_mode && iteration.is_some() && iteration.as_ref().unwrap().should_run(10) {
|
||||
@@ -1475,6 +1606,7 @@ pub async fn monitor_db(
|
||||
join!(
|
||||
expired_items_f,
|
||||
zombie_jobs_f,
|
||||
stale_jobs_f,
|
||||
expose_queue_metrics_f,
|
||||
verify_license_key_f,
|
||||
worker_groups_alerts_f,
|
||||
@@ -1557,6 +1689,30 @@ pub async fn expose_queue_metrics(db: &Pool<Postgres>) {
|
||||
let mut w = QUEUE_COUNT_TAGS.write().await;
|
||||
*w = tags_to_watch;
|
||||
}
|
||||
|
||||
#[cfg(feature = "prometheus")]
|
||||
if metrics_enabled {
|
||||
// Handle queue running count metrics
|
||||
let queue_running_counts = windmill_common::queue::get_queue_running_counts(db).await;
|
||||
|
||||
for q in QUEUE_RUNNING_COUNT_TAGS.read().await.iter() {
|
||||
if queue_running_counts.get(q).is_none() {
|
||||
(*QUEUE_RUNNING_COUNT).with_label_values(&[q]).set(0);
|
||||
}
|
||||
}
|
||||
|
||||
let mut running_tags_to_watch = vec![];
|
||||
for q in queue_running_counts {
|
||||
let count = q.1;
|
||||
let tag = q.0;
|
||||
|
||||
let metric = (*QUEUE_RUNNING_COUNT).with_label_values(&[&tag]);
|
||||
metric.set(count as i64);
|
||||
running_tags_to_watch.push(tag.to_string());
|
||||
}
|
||||
let mut w = QUEUE_RUNNING_COUNT_TAGS.write().await;
|
||||
*w = running_tags_to_watch;
|
||||
}
|
||||
}
|
||||
|
||||
// clean queue metrics older than 14 days
|
||||
@@ -1717,6 +1873,67 @@ pub async fn reload_base_url_setting(conn: &Connection) -> error::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn stale_job_cancellation(db: &Pool<Postgres>) {
|
||||
if let Some(threshold) = *STALE_JOB_TRESHOLD_MINUTES {
|
||||
let stale_jobs = sqlx::query!(
|
||||
"SELECT v2_job_queue.id, v2_job.tag, v2_job_queue.scheduled_for, v2_job_queue.workspace_id FROM v2_job_queue LEFT JOIN v2_job ON v2_job_queue.id = v2_job.id WHERE running = false AND scheduled_for < now() - ($1 || ' minutes')::interval",
|
||||
threshold.to_string()
|
||||
)
|
||||
.fetch_all(db)
|
||||
.await
|
||||
.ok()
|
||||
.unwrap_or_else(|| vec![]);
|
||||
|
||||
if !stale_jobs.is_empty() {
|
||||
tracing::info!(
|
||||
"Cancelling {} stale jobs (> {} minutes old)",
|
||||
stale_jobs.len(),
|
||||
threshold
|
||||
);
|
||||
}
|
||||
for job in stale_jobs {
|
||||
if let Err(e) =
|
||||
cancel_stale_job(db, job.id, job.tag, job.workspace_id, job.scheduled_for).await
|
||||
{
|
||||
tracing::error!("Error cancelling stale job {}: {}", job.id, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn cancel_stale_job(
|
||||
db: &Pool<Postgres>,
|
||||
id: Uuid,
|
||||
tag: String,
|
||||
workspace_id: String,
|
||||
scheduled_for: DateTime<Utc>,
|
||||
) -> error::Result<()> {
|
||||
let mut tx = db.begin().await?;
|
||||
tracing::error!(
|
||||
"Stale job detected: {} in workspace {} with tag {} (scheduled for: {}) . Cancelling it.",
|
||||
id,
|
||||
workspace_id,
|
||||
tag,
|
||||
scheduled_for
|
||||
);
|
||||
(tx, _) = cancel_job(
|
||||
"monitor",
|
||||
Some(format!(
|
||||
"Stale job cancellation (scheduled for: {})",
|
||||
scheduled_for
|
||||
)),
|
||||
id,
|
||||
&workspace_id,
|
||||
tx,
|
||||
db,
|
||||
true,
|
||||
false,
|
||||
)
|
||||
.await?;
|
||||
tx.commit().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
const RESTART_LIMIT: i32 = 3;
|
||||
|
||||
async fn handle_zombie_jobs(db: &Pool<Postgres>, base_internal_url: &str, worker_name: &str) {
|
||||
|
||||
@@ -959,6 +959,7 @@ impl RunJob {
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.expect("push has to succeed");
|
||||
@@ -3468,6 +3469,7 @@ async fn test_script_schedule_handlers(db: Pool<Postgres>) {
|
||||
tag: None,
|
||||
paused_until: None,
|
||||
cron_version: None,
|
||||
description: None,
|
||||
};
|
||||
|
||||
let _ = client.create_schedule("test-workspace", &schedule).await;
|
||||
@@ -3538,6 +3540,7 @@ async fn test_script_schedule_handlers(db: Pool<Postgres>) {
|
||||
tag: None,
|
||||
paused_until: None,
|
||||
cron_version: None,
|
||||
description: None,
|
||||
},
|
||||
)
|
||||
.await
|
||||
@@ -3621,6 +3624,7 @@ async fn test_flow_schedule_handlers(db: Pool<Postgres>) {
|
||||
tag: None,
|
||||
paused_until: None,
|
||||
cron_version: None,
|
||||
description: None,
|
||||
};
|
||||
|
||||
let _ = client.create_schedule("test-workspace", &schedule).await;
|
||||
@@ -3692,6 +3696,7 @@ async fn test_flow_schedule_handlers(db: Pool<Postgres>) {
|
||||
tag: None,
|
||||
paused_until: None,
|
||||
cron_version: None,
|
||||
description: None,
|
||||
},
|
||||
)
|
||||
.await
|
||||
@@ -3777,6 +3782,7 @@ async fn run_deployed_relative_imports(
|
||||
codebase: None,
|
||||
has_preprocessor: None,
|
||||
on_behalf_of_email: None,
|
||||
assets: vec![],
|
||||
},
|
||||
)
|
||||
.await
|
||||
@@ -4028,6 +4034,7 @@ async fn assert_lockfile(
|
||||
codebase: None,
|
||||
has_preprocessor: None,
|
||||
on_behalf_of_email: None,
|
||||
assets: vec![],
|
||||
},
|
||||
)
|
||||
.await
|
||||
|
||||
@@ -8213,6 +8213,9 @@ the execution of this script will be permissioned_as and by extension its DT_TOK
|
||||
Csharp,
|
||||
#[serde(rename = "nu")]
|
||||
Nu,
|
||||
#[serde(rename = "ruby")]
|
||||
Ruby,
|
||||
// for related places search: ADD_NEW_LANG
|
||||
}
|
||||
impl From<&ScriptLang> for ScriptLang {
|
||||
fn from(value: &ScriptLang) -> Self {
|
||||
@@ -8241,6 +8244,8 @@ the execution of this script will be permissioned_as and by extension its DT_TOK
|
||||
Self::Ansible => "ansible".to_string(),
|
||||
Self::Csharp => "csharp".to_string(),
|
||||
Self::Nu => "nu".to_string(),
|
||||
Self::Ruby => "ruby".to_string(),
|
||||
// for related places search: ADD_NEW_LANG
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8267,6 +8272,8 @@ the execution of this script will be permissioned_as and by extension its DT_TOK
|
||||
"ansible" => Ok(Self::Ansible),
|
||||
"csharp" => Ok(Self::Csharp),
|
||||
"nu" => Ok(Self::Nu),
|
||||
"ruby" => Ok(Self::Ruby),
|
||||
// for related places search: ADD_NEW_LANG
|
||||
_ => Err("invalid value"),
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user