Compare commits

...

183 Commits

Author SHA1 Message Date
Ruben Fiszel
b9ddc7e6c8 chore(main): release 1.14.5 (#142)
* chore(main): release 1.14.5

* Apply automatic changes

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2022-06-27 23:19:24 +02:00
Ruben Fiszel
d41913a440 fix: index.ts -> mod.ts 2022-06-27 23:17:31 +02:00
Ruben Fiszel
e07b5d4f30 fix: insert getResource proper parenthesis 2022-06-27 23:17:05 +02:00
Ruben Fiszel
880d98ca92 chore(main): release 1.14.4 (#141)
* chore(main): release 1.14.4

* Apply automatic changes

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2022-06-27 23:13:28 +02:00
Ruben Fiszel
8c0acac212 fix: windmill deno package index.ts -> mod.ts 2022-06-27 23:12:22 +02:00
Ruben Fiszel
9decbaf7a1 chore(main): release 1.14.3 (#140)
* chore(main): release 1.14.3

* Apply automatic changes

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2022-06-27 22:57:37 +02:00
Ruben Fiszel
63a7401f24 fix: internal state for script triggers v4 2022-06-27 22:55:18 +02:00
Ruben Fiszel
31445d7182 fix: internal state for script triggers v3 2022-06-27 22:53:40 +02:00
Ruben Fiszel
22c6347d8a fix: internal state for script triggers v3 2022-06-27 22:53:00 +02:00
Ruben Fiszel
315e2c7417 chore(main): release 1.14.2 (#139)
* chore(main): release 1.14.2

* Apply automatic changes

* Update CHANGELOG.md

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2022-06-27 22:45:45 +02:00
Ruben Fiszel
e7ae94eb45 fix: internal state for script triggers v2 2022-06-27 22:43:56 +02:00
Ruben Fiszel
f9eedc31ed fix: internal state for script triggers v2 2022-06-27 22:42:38 +02:00
Ruben Fiszel
f96d0fbda2 chore(main): release 1.14.1 (#138) 2022-06-27 22:03:58 +02:00
Ruben Fiszel
6321311112 fix: internal state for script triggers v1 2022-06-27 22:03:02 +02:00
Ruben Fiszel
8c5eb4de17 chore(main): release 1.14.0 (#128)
* chore(main): release 1.14.0

* Apply automatic changes

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2022-06-27 21:55:54 +02:00
Ruben Fiszel
dcdb989adb feat: internal state for script triggers mvp 2022-06-27 21:51:23 +02:00
github-actions[bot]
9fb7e6d37f sync hub items with community (#133)
* [create-pull-request] automated change

* Delete smtp.json

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@rubenfiszel.com>
2022-06-27 03:08:58 +02:00
Ruben Fiszel
66447bfff2 ci: pull hub items fix 2022-06-27 03:05:08 +02:00
Ruben Fiszel
4378c2d3f8 pass email to script hub fetching 2022-06-25 21:42:28 +02:00
Ruben Fiszel
472159d519 test hub and deploy 2022-06-25 03:42:48 +02:00
Ruben Fiszel
40e74e8e83 update windmill-gh-action-deploy 2022-06-25 03:40:41 +02:00
Ruben Fiszel
d4c698838b test hub and deploy 2022-06-25 03:36:15 +02:00
Ruben Fiszel
c6bfd74ed3 fix paths for ci actions 2022-06-25 03:35:44 +02:00
Ruben Fiszel
4cfd86d1d0 change community items to fit hub 2022-06-25 03:32:23 +02:00
Ruben Fiszel
81f0e85c8d add Pull Hub Items github action 2022-06-25 03:15:09 +02:00
Ruben Fiszel
5b8905ed02 add Pull Hub Items github action 2022-06-25 03:11:35 +02:00
Ruben Fiszel
85286c300e add pull_hub script 2022-06-25 03:07:44 +02:00
Ruben Fiszel
a50b8d4540 frontend: remove WIP for deno 2022-06-24 22:32:01 +02:00
Ruben Fiszel
bb946ed551 fix: smart assistant reload 2022-06-24 22:25:04 +02:00
Ruben Fiszel
6c622bcc32 fix: deno exit after result logging 2022-06-24 21:57:55 +02:00
Ruben Fiszel
368779bfc5 grant workspace read 2022-06-24 20:18:22 +02:00
Ruben Fiszel
e0adf68838 sqlx fix 2022-06-24 19:32:38 +02:00
Ruben Fiszel
4947661b1d feat: deno run with --unstable 2022-06-24 19:22:17 +02:00
Ruben Fiszel
b10645ff65 remove quotas for premium workspaces 2022-06-24 19:20:27 +02:00
Ruben Fiszel
fdf95a065e fix: change default per page to 100 2022-06-23 21:16:17 +02:00
Ruben Fiszel
d69661bc37 (frontend) be more upfront about upcoming non-unlimited community features 2022-06-23 21:11:04 +02:00
Ruben Fiszel
6de9697d95 feat: add tesseract bin to worker image 2022-06-23 19:16:16 +02:00
Ruben Fiszel
f98f6429c1 fix: improve error handling 2022-06-23 19:09:40 +02:00
Ruben Fiszel
2efaf21915 fix: improve error handling 2022-06-23 19:00:17 +02:00
Ruben Fiszel
3e2ba96d8c reactive workspaces UI 2022-06-23 05:11:38 +02:00
Ruben Fiszel
2d02b7b2da split frontend common utilities 2022-06-23 05:06:07 +02:00
Ruben Fiszel
a5f08e578a language-client imports only if language is deno or python 2022-06-23 03:12:38 +02:00
Ruben Fiszel
fc0c38ffad fix: schemaPicker does not display editor by default 2022-06-23 02:05:44 +02:00
Ruben Fiszel
c30b31ea88 move gen as well to lib 2022-06-23 01:10:33 +02:00
Ruben Fiszel
99c861a903 fixing itemsType ts types 2022-06-22 23:27:33 +02:00
Ruben Fiszel
ecad14aa6a add frontend package task for windmill-components for reuse in hub 2022-06-22 23:10:08 +02:00
Ruben Fiszel
47a0be6b7e move to paths 2022-06-22 22:34:01 +02:00
Ruben Fiszel
7e4265e18f chore(main): release 1.13.0 (#115)
* chore(main): release 1.13.0

* Apply automatic changes

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2022-06-22 21:53:07 +02:00
Ruben Fiszel
276319d992 feat: better type narrowing for list and array types 2022-06-22 21:48:41 +02:00
Ruben Fiszel
6dc90a3906 fix: make email constraint case insensitive 2022-06-20 23:11:48 +02:00
Ian Eaves
026a449f37 Update README.md (#116)
😉
2022-06-20 19:55:34 +02:00
Ruben Fiszel
906f740a0d fix: fix webhook path for flows 2022-06-15 04:33:47 +02:00
Ruben Fiszel
680aebb996 chore(main): release 1.12.0 (#114)
* chore(main): release 1.12.0

* Apply automatic changes

* Update CHANGELOG.md

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2022-06-14 09:07:56 +02:00
Ruben Fiszel
28b5671402 fix: rename ResourceType -> Resource 2022-06-14 08:55:55 +02:00
Ruben Fiszel
e127d2f79f feat: add ResourceType<'name'> as deno signature arg type 2022-06-14 03:04:00 +02:00
Ruben Fiszel
359ef15fa2 fix: more flexible ResourceType MainArgSignature parser 2022-06-14 02:23:34 +02:00
Ruben Fiszel
7739c4beaa chore(main): release 1.11.0 (#112)
* chore(main): release 1.11.0

* Apply automatic changes

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2022-06-14 01:45:10 +02:00
Ruben Fiszel
f1ee5f3130 feat: add ResourceType<'name'> as deno signature arg type 2022-06-14 01:43:24 +02:00
Ruben Fiszel
a59b92706b fix(frontend): loadItems not called in script picker 2022-06-13 20:47:27 +02:00
Ruben Fiszel
9f235c404e fix: force c_ prefix for adding resource type 2022-06-12 16:09:54 +02:00
Ruben Fiszel
95d98fc8fe remove exec_fd for compatibility with older kernels 2022-06-12 14:42:31 +02:00
Ruben Fiszel
8c4999d528 fix DISABLE_NUSER 2022-06-12 13:55:04 +02:00
Ruben Fiszel
a72d6dcc40 chore(deps): update backend dependencies 2022-06-12 13:48:05 +02:00
Ruben Fiszel
cce46f9440 feat: add DISABLE_NUSER for older kernels 2022-06-12 13:30:40 +02:00
Ruben Fiszel
5afcb2b274 rm unecessary Caddyfile 2022-06-12 03:52:17 +02:00
Ruben Fiszel
0da602d2c7 chore(main): release 1.10.1 (#111)
* chore(main): release 1.10.1

* Apply automatic changes

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2022-06-12 03:45:23 +02:00
Ruben Fiszel
295e28fd43 fix: python-client verify ssl 2022-06-12 03:42:44 +02:00
Ruben Fiszel
c3526d3172 simplify dockerfile - remove unecessary caddy 2022-06-12 03:05:39 +02:00
Ruben Fiszel
c3d2fd6e52 chore(main): release 1.10.0 (#105)
* chore(main): release 1.10.0

* Apply automatic changes

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2022-06-12 02:01:27 +02:00
Ruben Fiszel
1a61d50076 feat: alpha hub integration + frontend user store fixes + script client base_url fix 2022-06-12 01:55:05 +02:00
Ruben Fiszel
f691f53224 chore(main): release 1.9.0 (#63)
* chore(main): release 1.9.0

* Apply automatic changes

* Update CHANGELOG.md

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2022-06-05 13:43:51 +02:00
Ruben Fiszel
55ec20f1de bump svelte-preprocess 2022-06-05 13:30:49 +02:00
Ruben Fiszel
f2348b5526 fix: remove annoying transitions for scripts and flows 2022-06-05 13:16:00 +02:00
Ruben Fiszel
75cdb228dc fix login bug 2022-06-03 21:00:13 +02:00
Ruben Fiszel
26b8fd159a fix login bug 2022-06-03 20:52:14 +02:00
Faton Ramadani
fc8b078101 Setup Cypress e2e tests (#91)
* Setup Cypress e2e tests

* Add login function

* Cypress github action setup

* Fix CI github action

* Properly setup node and install dependencies

* Wait on localhost to respond before running the tests

* Install missing dependencies

* Remove rust setup

* Stop caddy after installation

* Remove Caddy from CI

* Properly connect to DB

* CI clean up

* Run cypress after build

* Testing CI

* Restore commented code

* Fix docker image tag

* Fix tags

* Fix tag

* Fix tag

* Fix node_modules

* Fix postgres host name

* Bind

* Fix port

* Logs

* Fix DB Host

* Test GA

* Create docker network

* Get IP from container

* Try removing custom wait-on

* Correctly run cypress tests

* Print IP

* Add logs

* Debug docker

* Add logs

* Logs

* logs

* Fix DB hostname

* tring my way

* tring my way

* tring my way

* tring my way

* works

Co-authored-by: Ruben Fiszel <ruben@rubenfiszel.com>
2022-06-03 20:22:12 +02:00
Ruben Fiszel
20cabe3335 minor fixes 2022-06-03 19:39:37 +02:00
Ruben Fiszel
0fe276b564 fix login button 2022-06-02 12:12:42 +02:00
Ruben Fiszel
8a8dbcb582 contributors section in README 2022-06-01 20:28:20 +02:00
dependabot[bot]
587ce379d4 chore(deps-dev): bump @sveltejs/kit in /frontend (#88)
Bumps [@sveltejs/kit](https://github.com/sveltejs/kit/tree/HEAD/packages/kit) from 1.0.0-next.342 to 1.0.0-next.347.
- [Release notes](https://github.com/sveltejs/kit/releases)
- [Changelog](https://github.com/sveltejs/kit/blob/master/packages/kit/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/kit/commits/@sveltejs/kit@1.0.0-next.347/packages/kit)

---
updated-dependencies:
- dependency-name: "@sveltejs/kit"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-01 10:01:30 +02:00
dependabot[bot]
c8eedf7d77 chore(deps-dev): bump @typescript-eslint/parser in /frontend (#89)
Bumps [@typescript-eslint/parser](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/parser) from 5.26.0 to 5.27.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/parser/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.27.0/packages/parser)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/parser"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-01 10:01:14 +02:00
dependabot[bot]
ca436d1d2a chore(deps-dev): bump @sveltejs/adapter-static in /frontend (#87)
Bumps [@sveltejs/adapter-static](https://github.com/sveltejs/kit/tree/HEAD/packages/adapter-static) from 1.0.0-next.31 to 1.0.0-next.34.
- [Release notes](https://github.com/sveltejs/kit/releases)
- [Changelog](https://github.com/sveltejs/kit/blob/master/packages/adapter-static/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/kit/commits/@sveltejs/adapter-static@1.0.0-next.34/packages/adapter-static)

---
updated-dependencies:
- dependency-name: "@sveltejs/adapter-static"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-01 09:54:28 +02:00
dependabot[bot]
9876b22d62 chore(deps-dev): bump postcss-load-config in /frontend (#85)
Bumps [postcss-load-config](https://github.com/postcss/postcss-load-config) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/postcss/postcss-load-config/releases)
- [Changelog](https://github.com/postcss/postcss-load-config/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss-load-config/compare/v4.0.0...v4.0.1)

---
updated-dependencies:
- dependency-name: postcss-load-config
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-01 09:54:02 +02:00
dependabot[bot]
04093a9a14 chore(deps-dev): bump @typescript-eslint/eslint-plugin in /frontend (#86)
Bumps [@typescript-eslint/eslint-plugin](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/eslint-plugin) from 5.26.0 to 5.27.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v5.27.0/packages/eslint-plugin)

---
updated-dependencies:
- dependency-name: "@typescript-eslint/eslint-plugin"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-01 09:53:42 +02:00
dependabot[bot]
1f6946f09b chore(deps): bump @zerodevx/svelte-toast in /frontend (#80)
Bumps [@zerodevx/svelte-toast](https://github.com/zerodevx/svelte-toast) from 0.7.1 to 0.7.2.
- [Release notes](https://github.com/zerodevx/svelte-toast/releases)
- [Commits](https://github.com/zerodevx/svelte-toast/compare/v0.7.1...v0.7.2)

---
updated-dependencies:
- dependency-name: "@zerodevx/svelte-toast"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-01 09:52:46 +02:00
dependabot[bot]
5a14d4b7d8 chore(deps-dev): bump eslint-plugin-svelte3 in /frontend (#79)
Bumps [eslint-plugin-svelte3](https://github.com/sveltejs/eslint-plugin-svelte3) from 3.4.1 to 4.0.0.
- [Release notes](https://github.com/sveltejs/eslint-plugin-svelte3/releases)
- [Changelog](https://github.com/sveltejs/eslint-plugin-svelte3/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/eslint-plugin-svelte3/compare/v3.4.1...v4.0.0)

---
updated-dependencies:
- dependency-name: eslint-plugin-svelte3
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-01 09:51:47 +02:00
dependabot[bot]
645e01a970 chore(deps): bump regex from 1.5.5 to 1.5.6 in /backend (#74)
Bumps [regex](https://github.com/rust-lang/regex) from 1.5.5 to 1.5.6.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.5.5...1.5.6)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-01 09:50:53 +02:00
dependabot[bot]
ee9d9d25bc chore(deps-dev): bump @sveltejs/adapter-node in /frontend (#84)
Bumps [@sveltejs/adapter-node](https://github.com/sveltejs/kit/tree/HEAD/packages/adapter-node) from 1.0.0-next.73 to 1.0.0-next.78.
- [Release notes](https://github.com/sveltejs/kit/releases)
- [Changelog](https://github.com/sveltejs/kit/blob/master/packages/adapter-node/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/kit/commits/@sveltejs/adapter-node@1.0.0-next.78/packages/adapter-node)

---
updated-dependencies:
- dependency-name: "@sveltejs/adapter-node"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@rubenfiszel.com>
2022-06-01 09:49:04 +02:00
dependabot[bot]
fc19c3c247 chore(deps-dev): bump cssnano from 5.1.9 to 5.1.10 in /frontend (#82)
Bumps [cssnano](https://github.com/cssnano/cssnano) from 5.1.9 to 5.1.10.
- [Release notes](https://github.com/cssnano/cssnano/releases)
- [Commits](https://github.com/cssnano/cssnano/compare/cssnano@5.1.9...cssnano@5.1.10)

---
updated-dependencies:
- dependency-name: cssnano
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-01 09:48:17 +02:00
dependabot[bot]
54ca6362d6 chore(deps-dev): bump typescript from 4.6.4 to 4.7.2 in /frontend (#83)
Bumps [typescript](https://github.com/Microsoft/TypeScript) from 4.6.4 to 4.7.2.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](https://github.com/Microsoft/TypeScript/compare/v4.6.4...v4.7.2)

---
updated-dependencies:
- dependency-name: typescript
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-01 09:47:02 +02:00
Ruben Fiszel
772c5806c9 login or signup whiter font 2022-06-01 09:45:51 +02:00
Ruben Fiszel
3d7a03af5f cloudflare function uses manual redirect 2022-05-30 12:48:08 +02:00
Ruben Fiszel
ac1cbba238 frontend: small fixes 2022-05-29 14:28:11 +02:00
Ruben Fiszel
d2078f175e frontend: small fixes 2022-05-29 14:27:24 +02:00
Ruben Fiszel
720093962a frontend: small fixes 2022-05-29 10:29:13 +02:00
Ruben Fiszel
e471a1d646 ci: more consistent docker image names 2022-05-26 00:49:41 +02:00
Faton Ramadani
9e6ab11484 Authentication refactor (#65)
* Refactor login logic

* Derive username from user + fix initial redirection if logged in

* Simplify how login navigation works

* Restore redirection

* Redirect to login page when not logged in

* Fix PR issues

* Add missing refreshSuperadmin when reloading a page with a valid token

* Explicitly clearing stores when logging out.

Co-authored-by: Ruben Fiszel <ruben@rubenfiszel.com>
2022-05-24 17:05:40 +02:00
dependabot[bot]
06eb50fbf2 chore(deps-dev): bump openapi-typescript-codegen in /frontend (#70)
Bumps [openapi-typescript-codegen](https://github.com/ferdikoomen/openapi-typescript-codegen) from 0.11.8 to 0.22.0.
- [Release notes](https://github.com/ferdikoomen/openapi-typescript-codegen/releases)
- [Changelog](https://github.com/ferdikoomen/openapi-typescript-codegen/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ferdikoomen/openapi-typescript-codegen/commits/v0.22.0)

---
updated-dependencies:
- dependency-name: openapi-typescript-codegen
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-05-24 16:44:39 +02:00
dependabot[bot]
40a380e9ec chore(deps-dev): bump postcss-load-config in /frontend (#71)
Bumps [postcss-load-config](https://github.com/postcss/postcss-load-config) from 3.1.4 to 4.0.0.
- [Release notes](https://github.com/postcss/postcss-load-config/releases)
- [Changelog](https://github.com/postcss/postcss-load-config/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss-load-config/compare/v3.1.4...v4.0.0)

---
updated-dependencies:
- dependency-name: postcss-load-config
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-05-24 16:41:06 +02:00
dependabot[bot]
c638f7a132 chore(deps-dev): bump @sveltejs/kit from 1.0.0-next.338 to 1.0.0-next.342 in /frontend (#78)
* chore(deps-dev): bump @sveltejs/kit in /frontend

Bumps [@sveltejs/kit](https://github.com/sveltejs/kit/tree/HEAD/packages/kit) from 1.0.0-next.338 to 1.0.0-next.342.
- [Release notes](https://github.com/sveltejs/kit/releases)
- [Changelog](https://github.com/sveltejs/kit/blob/master/packages/kit/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/kit/commits/@sveltejs/kit@1.0.0-next.342/packages/kit)

---
updated-dependencies:
- dependency-name: "@sveltejs/kit"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

* breaking changes

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@rubenfiszel.com>
2022-05-24 16:40:21 +02:00
Ruben Fiszel
d2f4a552c9 update eslint + prettify 2022-05-24 16:30:32 +02:00
Ruben Fiszel
479a12f33c feat: update postgres 13->14 in docker-compose 2022-05-24 16:21:57 +02:00
Ruben Fiszel
58e2a5c179 add cloudflare pages redirection 2022-05-24 14:24:15 +02:00
Ruben Fiszel
281fbc3671 edit .nvmrc 2022-05-24 14:04:26 +02:00
Ruben Fiszel
ffc58ab6c2 add .nvmrc 2022-05-24 13:58:20 +02:00
dependabot[bot]
0ea96f82d1 chore(deps-dev): bump eslint from 7.32.0 to 8.16.0 in /frontend (#69)
Bumps [eslint](https://github.com/eslint/eslint) from 7.32.0 to 8.16.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v7.32.0...v8.16.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-05-24 12:57:33 +02:00
Ruben Fiszel
e905d65ca6 fix: update monaco language-client for better lsp support 2022-05-23 13:23:37 +02:00
Ruben Fiszel
dc70dfcf74 fix: bypass RLS for admin at init-db.sql 2022-05-23 12:00:56 +02:00
Ruben Fiszel
9b79cc9870 fix: update monaco language-client for better lsp support 2022-05-21 10:56:54 +02:00
Ruben Fiszel
68a3e1b333 fix: update monaco language-client for better lsp support 2022-05-21 10:50:04 +02:00
Ruben Fiszel
917717373f fix: update monaco language-client for better lsp support 2022-05-21 10:36:53 +02:00
Ruben Fiszel
b61fb6dc30 fix: update monaco language-client for better lsp support 2022-05-21 09:05:03 +02:00
Ruben Fiszel
42aa386119 fix: update monaco language-client for better lsp support 2022-05-20 18:40:17 +02:00
Ruben Fiszel
d601ef9439 chore(main): release 1.8.6 (#62)
* chore(main): release 1.8.6

* Apply automatic changes

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2022-05-18 23:34:48 +02:00
Ruben Fiszel
d31cd3c52c fix: re-release 2022-05-18 23:33:33 +02:00
Ruben Fiszel
eb613c35c1 chore(main): release 1.8.5 (#61) 2022-05-18 23:28:42 +02:00
Ruben Fiszel
33fed8e04d fix: language field broke flow too 2022-05-18 23:28:09 +02:00
Ruben Fiszel
37afd486fd chore(main): release 1.8.4 (#60)
* chore(main): release 1.8.4

* Apply automatic changes

* Update CHANGELOG.md

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2022-05-18 22:58:34 +02:00
Ruben Fiszel
f76eede3b0 rebuild v8 is lockfile changed 2022-05-18 22:53:46 +02:00
Ruben Fiszel
7564d2cb1e fix: run scirpt 2022-05-18 22:50:56 +02:00
Ruben Fiszel
f12fe85fef chore(main): release 1.8.3 (#59)
* chore(main): release 1.8.3

* Apply automatic changes

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2022-05-18 10:13:12 +02:00
Ruben Fiszel
fd9285563a add v8.snap to .gitignore 2022-05-18 10:10:56 +02:00
Ruben Fiszel
605c2b4d11 fix: clean exported deno-client api 2022-05-18 10:09:41 +02:00
Ruben Fiszel
18b4ab2e73 fix publish pypi 2022-05-18 09:53:46 +02:00
Ruben Fiszel
02fb2b3806 chore(main): release 1.8.2 (#58)
* chore(main): release 1.8.2

* Apply automatic changes

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2022-05-18 09:50:12 +02:00
Ruben Fiszel
563ba3e7f7 fix: deno client 2022-05-18 09:48:41 +02:00
Ruben Fiszel
3eed59fcb1 fix: deno lsp client 2022-05-18 01:32:00 +02:00
Ruben Fiszel
7365a8e87b fix: starting deno script is now async 2022-05-17 23:15:16 +02:00
Ruben Fiszel
dbd6142997 align jsonrpc 2022-05-17 23:01:02 +02:00
Ruben Fiszel
865d728224 fix: deno lsp uses wss instead of ws 2022-05-17 22:39:57 +02:00
Ruben Fiszel
8861e19564 ci: add deno 2022-05-17 22:21:45 +02:00
Ruben Fiszel
92b502d9ba chore(main): release 1.8.1 (#57)
* chore(main): release 1.8.1

* Apply automatic changes

* Apply automatic changes

* Apply automatic changes

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2022-05-17 21:49:10 +02:00
Ruben Fiszel
297a3e60e2 ci: fix change version 2022-05-17 21:47:36 +02:00
Ruben Fiszel
1decaafde0 remove poetry locks 2022-05-17 21:43:15 +02:00
Ruben Fiszel
a7ef616c0d ci: fix change version 2022-05-17 21:39:10 +02:00
Ruben Fiszel
481685a73e ci: fix change version 2022-05-17 21:36:49 +02:00
Ruben Fiszel
a356e7b7d3 ci: use python poetry for change versions 2022-05-17 21:35:10 +02:00
Ruben Fiszel
f793bc46d9 fix: frontend dependencies update 2022-05-17 21:30:10 +02:00
Ruben Fiszel
c49e4930bc update frontend 2022-05-17 21:28:24 +02:00
dependabot[bot]
7b6ae612a5 chore(deps): bump @codingame/monaco-jsonrpc in /frontend (#55)
Bumps [@codingame/monaco-jsonrpc](https://github.com/CodinGame/monaco-jsonrpc) from 0.3.1 to 0.4.0.
- [Release notes](https://github.com/CodinGame/monaco-jsonrpc/releases)
- [Commits](https://github.com/CodinGame/monaco-jsonrpc/commits)

---
updated-dependencies:
- dependency-name: "@codingame/monaco-jsonrpc"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-05-17 21:20:40 +02:00
dependabot[bot]
d179d6efc3 chore(deps): bump @zerodevx/svelte-toast in /frontend (#56)
Bumps [@zerodevx/svelte-toast](https://github.com/zerodevx/svelte-toast) from 0.6.3 to 0.7.1.
- [Release notes](https://github.com/zerodevx/svelte-toast/releases)
- [Commits](https://github.com/zerodevx/svelte-toast/compare/v0.6.3...v0.7.1)

---
updated-dependencies:
- dependency-name: "@zerodevx/svelte-toast"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-05-17 21:19:08 +02:00
Ruben Fiszel
f02e5b19ac update frontend + lock python client 2022-05-17 21:16:36 +02:00
Ruben Fiszel
e114d0f426 chore(main): release 1.8.0 (#52)
* chore(main): release 1.8.0

* Apply automatic changes

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2022-05-17 20:53:14 +02:00
Ruben Fiszel
03ec38e001 update cargo 2022-05-17 20:52:42 +02:00
Ruben Fiszel
2e1d43033f feat: Typescript support for scripts (alpha)
* typescript support

* frontend

* type inference

* type inference

* v0 works

* v0 typescript

* v0 typescript

* deno-client v0

* deno-client v0

* build_deno

* rm autogenerated files

* test workflow

* test workflow

* test workflow

* test workflow

* test workflow

* test workflow

* test workflow

* test workflow

* test workflow

* test workflow

* test workflow

* test workflow

* test workflow

* test workflow

* test workflow

* test workflow

* test workflow

* test workflow

* on tags

* createResource

* createResource

* createResource2

* typescript support

* templates

* include version
2022-05-17 20:42:05 +02:00
Ruben Fiszel
ec528fce67 chore(main): release 1.7.0 (#45)
* chore(main): release 1.7.0

* Apply automatic changes

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2022-05-14 14:58:31 +02:00
Tomasz Wsuł
5b413d7e04 feat: self host github oauth (#46) 2022-05-14 14:54:53 +02:00
Ruben Fiszel
02c8bea084 fix: better error message when saving script 2022-05-11 13:29:21 +02:00
Ruben Fiszel
bb31c80378 fix README docker-compose reference 2022-05-11 13:05:22 +02:00
Ruben Fiszel
91045e73cc BUG_ISSUE instructions 2022-05-11 08:10:51 +02:00
dependabot[bot]
9219b651a3 chore(deps-dev): bump @sveltejs/kit in /frontend (#25)
Bumps [@sveltejs/kit](https://github.com/sveltejs/kit/tree/HEAD/packages/kit) from 1.0.0-next.324 to 1.0.0-next.326.
- [Release notes](https://github.com/sveltejs/kit/releases)
- [Changelog](https://github.com/sveltejs/kit/blob/master/packages/kit/CHANGELOG.md)
- [Commits](https://github.com/sveltejs/kit/commits/@sveltejs/kit@1.0.0-next.326/packages/kit)

---
updated-dependencies:
- dependency-name: "@sveltejs/kit"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@rubenfiszel.com>
2022-05-11 01:27:27 +02:00
Ruben Fiszel
7f21d03d00 chore(main): release 1.6.1 (#34)
* chore(main): release 1.6.1

* Apply automatic changes

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2022-05-10 21:38:59 +02:00
dependabot[bot]
a62e6e5ee3 chore(deps): bump serde_json from 1.0.79 to 1.0.81 in /backend (#26)
Bumps [serde_json](https://github.com/serde-rs/json) from 1.0.79 to 1.0.81.
- [Release notes](https://github.com/serde-rs/json/releases)
- [Commits](https://github.com/serde-rs/json/compare/v1.0.79...v1.0.81)

---
updated-dependencies:
- dependency-name: serde_json
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@rubenfiszel.com>
2022-05-10 21:32:22 +02:00
Ruben Fiszel
2c28031e44 fix: also store and display "started at" for completed jobs (#33) 2022-05-10 21:32:07 +02:00
Ruben Fiszel
ca8de69126 run prettier 2022-05-10 21:29:54 +02:00
dependabot[bot]
98071bd68b chore(deps): bump tower-http from 0.2.5 to 0.3.3 in /backend (#27)
Bumps [tower-http](https://github.com/tower-rs/tower-http) from 0.2.5 to 0.3.3.
- [Release notes](https://github.com/tower-rs/tower-http/releases)
- [Commits](https://github.com/tower-rs/tower-http/compare/tower-http-0.2.5...tower-http-0.3.3)

---
updated-dependencies:
- dependency-name: tower-http
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@rubenfiszel.com>
2022-05-10 21:18:04 +02:00
dependabot[bot]
128dde4fb3 chore(deps): bump thiserror from 1.0.30 to 1.0.31 in /backend (#30)
Bumps [thiserror](https://github.com/dtolnay/thiserror) from 1.0.30 to 1.0.31.
- [Release notes](https://github.com/dtolnay/thiserror/releases)
- [Commits](https://github.com/dtolnay/thiserror/compare/1.0.30...1.0.31)

---
updated-dependencies:
- dependency-name: thiserror
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@rubenfiszel.com>
2022-05-10 21:07:45 +02:00
dependabot[bot]
f090945b27 chore(deps): bump serde from 1.0.136 to 1.0.137 in /backend (#32) 2022-05-10 21:07:29 +02:00
dependabot[bot]
60729d80b9 chore(deps): bump mhart/alpine-node from 14 to 16 (#21)
Bumps mhart/alpine-node from 14 to 16.

---
updated-dependencies:
- dependency-name: mhart/alpine-node
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ruben Fiszel <ruben@rubenfiszel.com>
2022-05-10 17:28:49 +02:00
Ruben Fiszel
e228beec2a ci: push to private registry builded image no matter what 2022-05-10 17:15:16 +02:00
dependabot[bot]
4dbf562fb7 chore(deps): bump GoogleCloudPlatform/release-please-action from 2 to 3 (#20) 2022-05-10 14:41:11 +02:00
dependabot[bot]
4952290296 chore(deps): bump actions/checkout from 2 to 3 (#19)
Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-05-10 14:24:17 +02:00
Juan Calderon-Perez
f53eb71e4a ci: add support for dependabot (#9)
* Add support for dependabot

* Add dependabot support for Python clients

* move to a weekly schedule

Co-authored-by: Ruben Fiszel <ruben@rubenfiszel.com>
2022-05-10 12:14:38 +00:00
Ruben Fiszel
96f54f5f44 chore: release 1.6.0 (#6)
* Apply automatic changes

* Update version.txt

* Apply automatic changes

* Update CHANGELOG.md

Co-authored-by: rubenfiszel <rubenfiszel@users.noreply.github.com>
2022-05-10 12:48:04 +02:00
Ruben Fiszel
0863e12e6a ci: add codeowners 2022-05-10 09:41:44 +02:00
Ruben Fiszel
d03266b0a4 ci: add CLA 2022-05-10 09:12:24 +02:00
Ruben Fiszel
4a4eaa90e2 ci: add CLA 2022-05-10 09:02:28 +02:00
Ruben Fiszel
5e7c14b722 ci: add CLA 2022-05-10 08:52:11 +02:00
Ruben Fiszel
55b5695673 fix: display more than default 30 workspaces as superadmin 2022-05-09 15:18:28 +02:00
Ruben Fiszel
8596ac50b9 delete starter script without lock files 2022-05-08 17:56:16 +02:00
Ruben Fiszel
13fb52117b feat: self host minimal 2 2022-05-08 17:51:33 +02:00
Ruben Fiszel
2c70a15594 feat: self host minimal 2022-05-08 17:26:51 +02:00
Ruben Fiszel
7a51f842f0 feat: superadmin settings 2022-05-08 17:03:13 +02:00
Ruben Fiszel
a130806e19 feat: user settings is now at workspace level 2022-05-08 12:58:58 +02:00
Ruben Fiszel
fd1f05dd16 ci: refactor + dockerhub 2022-05-08 11:57:37 +02:00
Ruben Fiszel
48e51733e0 docs: add main ci badge 2022-05-06 14:59:42 +02:00
Ruben Fiszel
e7817e6c9f alpha.windmill -> app.windmill 2022-05-06 13:55:14 +02:00
Ruben Fiszel
51ad6edfcb docs: typos 2022-05-05 15:59:59 +02:00
Ruben Fiszel
315f7edd64 docs: windmill imgs 2022-05-05 15:53:40 +02:00
Ruben Fiszel
a2c3deab74 docs: README general idea 2022-05-05 15:24:35 +02:00
Ruben Fiszel
891b7eb93a docs: architecture diagram 2022-05-05 13:22:13 +02:00
Ruben Fiszel
7efd87be79 docs: architecture diagram 2022-05-05 13:20:42 +02:00
Ruben Fiszel
5acbc8b48c Create FUNDING.yml 2022-05-05 10:50:54 +02:00
232 changed files with 10662 additions and 6357 deletions

6
.env
View File

@@ -1,3 +1,5 @@
SITE_URL=localhost
DB_PASSWORD=changeme
POSTGRES_VERSION=13.3.0
# GitHub OAuth- https://docs.github.com/en/developers/apps/building-oauth-apps/creating-an-oauth-app
GITHUB_OAUTH_CLIENT_ID=yours_client_id
GITHUB_OAUTH_CLIENT_SECRET=yours_client_sected

1
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1 @@
* @rubenfiszel

3
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,3 @@
# These are supported funding model platforms
github: [rubenfiszel]

View File

@@ -1,38 +1,27 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
title: 'bug:'
labels: 'bug'
assignees: 'rubenfiszel'
---
**Describe the bug**
A clear and concise description of what the bug is.
**Describe the bug** A clear and concise description of what the bug is.
**To Reproduce** Steps to reproduce the behavior:
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Expected behavior** A clear and concise description of what you expected to
happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Screenshots** If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
**Windmill version** Go on the left menu -> <user> -> User Settings and copy the
printed version in "Running windmill version (backend): XXX".
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
**Additional context** Add any other context about the problem here.

View File

@@ -0,0 +1,8 @@
---
name: Feature Request
about: Create a feature request
title: 'feature: '
labels: 'feature'
assignees: 'rubenfiszel'
---

View File

@@ -9,8 +9,10 @@ sed -i -e "/\"version\": /s/: .*,/: \"$VERSION\",/" frontend/package.json
sed -i -e "/^version =/s/= .*/= \"$VERSION\"/" python-client/wmill/pyproject.toml
sed -i -e "/^windmill-api =/s/= .*/= \"\\^$VERSION\"/" python-client/wmill/pyproject.toml
sed -i -e "/^version =/s/= .*/= \"$VERSION\"/" python-client/wmill_pg/pyproject.toml
sed -i -e "/^wmill =/s/= .*/= \"\\^$VERSION\"/" python-client/wmill_pg/pyproject.toml
sed -i -e "/^wmill =/s/= .*/= \">=$VERSION\"/" Pipfile
sed -i -e "/^wmill_pg =/s/= .*/= \">=$VERSION\"/" Pipfile
# sed -i -e "/^wmill =/s/= .*/= \"\\^$VERSION\"/" python-client/wmill_pg/pyproject.toml
sed -i -e "/^wmill =/s/= .*/= \">=$VERSION\"/" lsp/Pipfile
sed -i -e "/^wmill_pg =/s/= .*/= \">=$VERSION\"/" lsp/Pipfile
sed -i -zE "s/name = \"windmill\"\nversion = \"[^\"]*\"\\n(.*)/name = \"windmill\"\nversion = \"$VERSION\"\\n\\1/" backend/Cargo.lock
cd frontend && npm i --package-lock-only

39
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
# Basic set up for three package managers
version: 2
updates:
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
# Maintain dependencies for npm
- package-ecosystem: "npm"
directory: "/frontend"
schedule:
interval: "weekly"
# Maintain dependencies for cargo
- package-ecosystem: "cargo"
directory: "/backend"
schedule:
interval: "weekly"
# Maintain dependencies for Docker
- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
# Maintain dependencies for wmill python client
- package-ecosystem: "pip"
directory: "/python-client/wmill"
schedule:
interval: "weekly"
# Maintain dependencies for wmill_pg python client
- package-ecosystem: "pip"
directory: "/python-client/wmill_pg"
schedule:
interval: "weekly"

13
.github/pull_hub_items.sh vendored Executable file
View File

@@ -0,0 +1,13 @@
#!/bin/bash
RT=$(curl -s https://hub.windmill.dev/resource_types/list | jq -c -r '.[]')
for item in ${RT[@]}; do
name=$(jq -r '.name' <<< "$item")
id=$(jq -r '.id' <<< "$item")
echo $name $id
body=$(curl -s -H "accept: application/json" https://hub.windmill.dev/resource_types/${id}/${name})
jq -r '.resource_type.schema' <<< "$body" > ./tmp
description=$(jq -r '.resource_type.description' <<< "$body")
echo "{\"workspace_id\": \"starter\", \"name\": \"$name\", \"schema\": $(cat ./tmp), \"description\": \"$description\"} " | jq . > community/resource_types/${name}.json
rm ./tmp
done

View File

@@ -7,8 +7,9 @@ on:
jobs:
change_version:
runs-on: ubuntu-latest
container: node:18
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Change versions
run: ./.github/change-versions.sh "$(cat version.txt)"
- uses: stefanzweifel/git-auto-commit-action@v4

49
.github/workflows/deno_on_release.yml vendored Normal file
View File

@@ -0,0 +1,49 @@
name: Publish deno-client
on:
push:
tags:
- "v*"
env:
repo: windmill-deno-client
jobs:
build_deno_and_push_to_repo:
runs-on: ubuntu-latest
container: openapitools/openapi-generator-cli:v6.0.0-beta
steps:
- uses: actions/checkout@v3
- name: generate_deno
run: |
cd deno-client
rm .gitignore
./generate.sh
- name: Pushes to another repository
id: push_directory
uses: cpina/github-action-push-to-another-repository@devel
env:
API_TOKEN_GITHUB: ${{ secrets.DENO_PAT }}
with:
source-directory: deno-client/
destination-github-username: ${{ github.repository_owner }}
destination-repository-name: ${{ env.repo }}
user-email: ruben@windmill.dev
commit-message: See ORIGIN_COMMIT from $GITHUB_REF
target-branch: main
tag_repo:
needs: [build_deno_and_push_to_repo]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
repository: ${{ github.repository_owner }}/${{ env.repo }}
token: ${{ secrets.DENO_PAT }}
path: ./client
- name: Push client
run: |
cd ./client
git config --global user.email "ruben@windmill.dev"
git config --global user.name "rubenfiszel[bot]"
git tag -a ${{ github.ref_name }} -m "${{ github.ref_name }}"
git push --tags

View File

@@ -3,6 +3,8 @@ name: Deploy to windmill.dev
on:
push:
branches: [main]
paths:
- "community/**"
jobs:
deploy:
@@ -10,7 +12,7 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Deploy to windmill.dev
uses: windmill-labs/windmill-gh-action-deploy@v1.0.0
uses: windmill-labs/windmill-gh-action-deploy@v2.0.0
with:
dry_run: false
input_dir: community

View File

@@ -1,7 +1,13 @@
name: Docker Image CI
env:
LOCAL_REGISTRY: registry.wimill.xyz
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
name: Build and push docker image
on:
push:
branches: [main]
tags: ["*"]
pull_request:
types: [opened, synchronize, reopened]
@@ -12,28 +18,97 @@ concurrency:
jobs:
build:
runs-on: [self-hosted, new]
env:
DOCKER_BUILDKIT: 1
steps:
- name: Wait for release to succeed
if: github.ref == 'refs/heads/main'
uses: lewagon/wait-on-check-action@v1.0.0
with:
ref: ${{ github.ref }}
check-name: "Release please"
repo-token: ${{ secrets.GITHUB_TOKEN }}
wait-interval: 10
- uses: actions/checkout@v2
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: deploy staging stack
run: |
docker build . --cache-from "registry.wimill.xyz/windmill:staging" -t "registry.wimill.xyz/windmill:staging" --build-arg BUILDKIT_INLINE_CACHE=1
docker push "registry.wimill.xyz/windmill:staging"
- name: deploy demo stack
if: github.ref == 'refs/heads/main'
run: |
docker tag registry.wimill.xyz/windmill:staging registry.wimill.xyz/windmill:main
docker push registry.wimill.xyz/windmill:main
# - name: pruning unused images
# run: sudo docker image prune -a
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Docker meta local
id: metalocal
uses: docker/metadata-action@v4
with:
images: ${{ env.LOCAL_REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Build and push privately
uses: docker/build-push-action@v3
if: github.event_name == 'pull_request'
with:
context: .
push: true
tags: |
${{ env.LOCAL_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
${{ steps.metalocal.outputs.tags }}
labels: ${{ steps.metalocal.outputs.labels }}
cache-from: type=registry,ref=${{ env.LOCAL_REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache
cache-to: type=registry,ref=${{ env.LOCAL_REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max
- name: Docker meta
if: github.event_name != 'pull_request'
id: meta
uses: docker/metadata-action@v4
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Login to registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v2
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push publically
uses: docker/build-push-action@v3
if: github.event_name != 'pull_request'
with:
context: .
push: true
tags: |
${{ env.LOCAL_REGISTRY }}/${{ env.IMAGE_NAME }}:latest
${{ steps.metalocal.outputs.tags }}
${{ steps.meta.outputs.tags }}
labels: ${{ steps.metalocal.outputs.labels }}
cache-from: type=registry,ref=${{ env.LOCAL_REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache
cache-to: type=registry,ref=${{ env.LOCAL_REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max
cypress:
runs-on: [self-hosted, new]
needs: [build]
services:
postgres:
image: postgres
env:
POSTGRES_DB: windmill
POSTGRES_USER: admin
POSTGRES_PASSWORD: changeme
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v3
- name: "Docker"
run: echo "::set-output name=id::$(docker run --network=host --rm -d -p 8000:8000 --privileged -it -e DATABASE_URL=postgres://admin:changeme@localhost:5432/windmill -e BASE_INTERNAL_URL=http://localhost:8000 ${{ env.LOCAL_REGISTRY }}/${{ env.IMAGE_NAME }}:latest)"
id: docker-container
- name: "Cypress run"
uses: cypress-io/github-action@v4
with:
working-directory: ./frontend
config: baseUrl=http://localhost:8000
- name: "Clean up"
run: docker kill ${{ steps.docker-container.outputs.id }}
if: always()

41
.github/workflows/lsp_on_release.yml vendored Normal file
View File

@@ -0,0 +1,41 @@
env:
LOCAL_REGISTRY: registry.wimill.xyz
IMAGE_NAME: ${{ github.repository }}
name: Publish LSP Server
on:
push:
branches: [main]
paths:
- "python-client/**"
- "lsp/**"
tags:
- "*"
jobs:
build:
runs-on: [self-hosted, new]
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Docker meta local
id: metalocal
uses: docker/metadata-action@v4
with:
images: ${{ env.LOCAL_REGISTRY }}/${{ env.IMAGE_NAME }}-lsp
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: Build and push
uses: docker/build-push-action@v3
with:
context: "{{defaultContext}}:lsp"
push: true
tags: ${{ steps.metalocal.outputs.tags }}
labels: ${{ steps.metalocal.outputs.labels }}
cache-from: type=registry,ref=${{ env.LOCAL_REGISTRY }}/${{ env.IMAGE_NAME }}-lsp:buildcache
cache-to: type=registry,ref=${{ env.LOCAL_REGISTRY }}/${{ env.IMAGE_NAME }}-lsp:buildcache,mode=max

View File

@@ -1,38 +0,0 @@
name: Build LSP Docker
on:
push:
branches: [main]
paths:
- "python-client/**"
- "Pipfile"
- ".github/workflows/on-release.yml"
jobs:
build_lsp:
runs-on: [self-hosted, new]
steps:
- name: Wait for release to succeed
if: github.ref == 'refs/heads/main'
uses: lewagon/wait-on-check-action@v1.0.0
with:
ref: ${{ github.ref }}
check-name: "Release please"
repo-token: ${{ secrets.GITHUB_TOKEN }}
wait-interval: 10
- uses: actions/checkout@v2
- name: Upload python client
env:
PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
cd python-client
export PATH=$PATH:/usr/local/bin
export PATH=$PATH:/root/.local/bin
./publish.sh
- name: Build the Docker image
run: |
cd lsp
sudo docker pull "registry.wimill.xyz/lsp:main" || true
sudo docker build . --cache-from "registry.wimill.xyz/lsp:main" -t "registry.wimill.xyz/lsp:main" --build-arg BUILDKIT_INLINE_CACHE=1
- name: push to registry
run: |
sudo docker push "registry.wimill.xyz/lsp:main"

19
.github/workflows/pull-hub.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: Pull Hub Items
on:
schedule:
# * is a special character in YAML so you have to quote this string
- cron: "0 0 */1 * *"
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
jobs:
change_version:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Pull hub
run: ./.github/pull_hub_items.sh
- name: Create Pull Request
uses: peter-evans/create-pull-request@v4
with:
title: sync hub items with community

19
.github/workflows/pypi_on_release.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: Publish python-client
on:
push:
tags:
- "v*"
jobs:
publish_pypi:
runs-on: [self-hosted, new]
steps:
- uses: actions/checkout@v3
- name: Upload python client
env:
PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
cd python-client
export PATH=$PATH:/usr/local/bin
export PATH=$PATH:/root/.local/bin
./publish.sh

View File

@@ -1,14 +1,14 @@
on:
push:
branches:
- main
branches: [main]
name: release-please
jobs:
release-please:
name: "Release please"
runs-on: ubuntu-latest
steps:
- uses: GoogleCloudPlatform/release-please-action@v2
- uses: GoogleCloudPlatform/release-please-action@v3
with:
release-type: simple
package-name: windmill

34
.github/workflows/sign-cla.yml vendored Normal file
View File

@@ -0,0 +1,34 @@
name: "CLA Assistant"
on:
issue_comment:
types: [created]
pull_request_target:
types: [opened, closed, synchronize]
jobs:
CLAssistant:
runs-on: ubuntu-latest
steps:
- name: "CLA Assistant"
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
# Beta Release
uses: cla-assistant/github-action@v2.1.3-beta
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PERSONAL_ACCESS_TOKEN: ${{ secrets.CLA_PAT }}
with:
path-to-signatures: "signatures/cla.json"
path-to-document: "https://github.com/windmill-labs/windmill/blob/master/CLA.md"
branch: "signatures"
allowlist: rubenfiszel,bot*
#below are the optional inputs - If the optional inputs are not given, then default values will be taken
#remote-organization-name: enter the remote organization name where the signatures should be stored (Default is storing the signatures in the same repository)
#remote-repository-name: enter the remote repository name where the signatures should be stored (Default is storing the signatures in the same repository)
#create-file-commit-message: 'For example: Creating file for storing CLA Signatures'
#signed-commit-message: 'For example: $contributorName has signed the CLA in #$pullRequestNo'
#custom-notsigned-prcomment: 'pull request comment with Introductory message to ask new contributors to sign'
#custom-pr-sign-comment: 'The signature to be committed in order to sign the CLA'
#custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.'
#lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true)
#use-dco-flag: true - If you are using DCO instead of CLA

View File

@@ -1,3 +1,204 @@
# Changelog
## [1.14.5](https://github.com/windmill-labs/windmill/compare/v1.14.4...v1.14.5) (2022-06-27)
### Bug Fixes
* index.ts -> mod.ts ([d41913a](https://github.com/windmill-labs/windmill/commit/d41913a440b2034de59437488edc85e38c956d5f))
* insert getResource proper parenthesis ([e07b5d4](https://github.com/windmill-labs/windmill/commit/e07b5d4f30ea79a99caac4fb63a9ab1f17eaaf74))
## [1.14.4](https://github.com/windmill-labs/windmill/compare/v1.14.3...v1.14.4) (2022-06-27)
### Bug Fixes
* windmill deno package index.ts -> mod.ts ([8c0acac](https://github.com/windmill-labs/windmill/commit/8c0acac212d742acee8b7ff0cf6b93cce4187c19))
## [1.14.3](https://github.com/windmill-labs/windmill/compare/v1.14.2...v1.14.3) (2022-06-27)
### Bug Fixes
* internal state for script triggers v3 ([31445d7](https://github.com/windmill-labs/windmill/commit/31445d7182a910eab9d699760f2a86ca23d556a4))
* internal state for script triggers v3 ([22c6347](https://github.com/windmill-labs/windmill/commit/22c6347d8a74d94dc18109390ff5c347a2732823))
* internal state for script triggers v4 ([63a7401](https://github.com/windmill-labs/windmill/commit/63a7401f248cc37951bbea4dcaedaa6497d6f0b1))
## [1.14.2](https://github.com/windmill-labs/windmill/compare/v1.14.1...v1.14.2) (2022-06-27)
### Bug Fixes
* internal state for script triggers v2 ([f9eedc3](https://github.com/windmill-labs/windmill/commit/f9eedc31ed6e5d7e0a8a26633cca9965ac3b6a05))
## [1.14.1](https://github.com/windmill-labs/windmill/compare/v1.14.0...v1.14.1) (2022-06-27)
### Bug Fixes
* internal state for script triggers v1 ([6321311](https://github.com/windmill-labs/windmill/commit/6321311112dfa3ef09447f41847b248c0e0dcb46))
## [1.14.0](https://github.com/windmill-labs/windmill/compare/v1.13.0...v1.14.0) (2022-06-27)
### Features
* add tesseract bin to worker image ([6de9697](https://github.com/windmill-labs/windmill/commit/6de9697d955a06cfb9c64fdb501b4dfa1bb597ad))
* deno run with --unstable ([4947661](https://github.com/windmill-labs/windmill/commit/4947661b1d91867c022bb8a10a4be3e91f69352c))
* internal state for script triggers mvp ([dcdb989](https://github.com/windmill-labs/windmill/commit/dcdb989adb8350974289a0c8d2239b245a6e0d41))
### Bug Fixes
* change default per page to 100 ([fdf95a0](https://github.com/windmill-labs/windmill/commit/fdf95a065e83d733ab6a0f02edb4af16c0a1dfb9))
* deno exit after result logging ([6c622bc](https://github.com/windmill-labs/windmill/commit/6c622bcc32473361e1f7cb1ea7b0b508929bc1b8))
* improve error handling ([f98f642](https://github.com/windmill-labs/windmill/commit/f98f6429c1e646c0a836f2f73a03a803aa655583))
* improve error handling ([2efaf21](https://github.com/windmill-labs/windmill/commit/2efaf2191551c1406618c6d60bd37ca6eff84560))
* schemaPicker does not display editor by default ([fc0c38f](https://github.com/windmill-labs/windmill/commit/fc0c38ffad18a9ceda44cb8406736c14ba4eb4c2))
* smart assistant reload ([bb946ed](https://github.com/windmill-labs/windmill/commit/bb946ed5519f59adc559d6959c56e61403389c9d))
## [1.13.0](https://github.com/windmill-labs/windmill/compare/v1.12.0...v1.13.0) (2022-06-22)
### Features
* better type narrowing for list and array types ([276319d](https://github.com/windmill-labs/windmill/commit/276319d99240dbca5bcc74a1142d99ca823c4da2))
### Bug Fixes
* fix webhook path for flows ([906f740](https://github.com/windmill-labs/windmill/commit/906f740a0ddce26743e4669af7a101613131a17c))
* make email constraint case insensitive ([6dc90a3](https://github.com/windmill-labs/windmill/commit/6dc90a390643fcf6116289596ca1c3149d326797))
## [1.12.0](https://github.com/windmill-labs/windmill/compare/v1.11.0...v1.12.0) (2022-06-14)
### Bug Fixes
* more flexible ResourceType MainArgSignature parser ([359ef15](https://github.com/windmill-labs/windmill/commit/359ef15fa2a9024507a71f2c656373925fba3ebe))
* rename ResourceType -> Resource ([28b5671](https://github.com/windmill-labs/windmill/commit/28b56714023ea69a20f003e08f6c40de64202ac5))
## [1.11.0](https://github.com/windmill-labs/windmill/compare/v1.10.1...v1.11.0) (2022-06-13)
### Features
* add DISABLE_NUSER for older kernels ([cce46f9](https://github.com/windmill-labs/windmill/commit/cce46f94404ac5c10407e430fff8cdec3bd7fb2d))
* add ResourceType<'name'> as deno signature arg type ([f1ee5f3](https://github.com/windmill-labs/windmill/commit/f1ee5f3130cb7b753ccc3ee62169c5e4a8ef7b8b))
### Bug Fixes
* force c_ prefix for adding resource type ([9f235c4](https://github.com/windmill-labs/windmill/commit/9f235c404ed62b54a73451b9f9dbddd8f013120d))
* **frontend:** loadItems not called in script picker ([a59b927](https://github.com/windmill-labs/windmill/commit/a59b92706b24a07cc14288620a9bcdb9402bd134))
## [1.10.1](https://github.com/windmill-labs/windmill/compare/v1.10.0...v1.10.1) (2022-06-12)
### Bug Fixes
* python-client verify ssl ([295e28f](https://github.com/windmill-labs/windmill/commit/295e28fd43ef07b739d2c7c85b0ae6819f7d7434))
## [1.10.0](https://github.com/windmill-labs/windmill/compare/v1.9.0...v1.10.0) (2022-06-11)
### Features
* alpha hub integration + frontend user store fixes + script client base_url fix ([1a61d50](https://github.com/windmill-labs/windmill/commit/1a61d50076b295fe97e48c2a621dff30802152b1))
## [1.9.0](https://github.com/windmill-labs/windmill/compare/v1.8.6...v1.9.0) (2022-06-05)
### Features
* update postgres 13->14 in docker-compose ([479a12f](https://github.com/windmill-labs/windmill/commit/479a12f33ca26bfd1b67bcdd24a64ca26cc6bebe))
### Bug Fixes
* remove annoying transitions for scripts and flows ([f2348b5](https://github.com/windmill-labs/windmill/commit/f2348b5526bb8197519685cb57049f74c6f3a11d))
### [1.8.6](https://github.com/windmill-labs/windmill/compare/v1.8.5...v1.8.6) (2022-05-18)
### Bug Fixes
* re-release ([d31cd3c](https://github.com/windmill-labs/windmill/commit/d31cd3c52c1b46e821da261f22d0aec872b61fb2))
### [1.8.5](https://github.com/windmill-labs/windmill/compare/v1.8.4...v1.8.5) (2022-05-18)
### Bug Fixes
* language field broke flow too ([33fed8e](https://github.com/windmill-labs/windmill/commit/33fed8e04d3abbde371535ecb6e7ba15d103db92))
### [1.8.4](https://github.com/windmill-labs/windmill/compare/v1.8.3...v1.8.4) (2022-05-18)
### Bug Fixes
* scripts run was broken due to 1.7 and 1.8 changes. This fix it ([7564d2c](https://github.com/windmill-labs/windmill/commit/7564d2cb1e7f600ede22f333a02a537df381d829))
### [1.8.3](https://github.com/windmill-labs/windmill/compare/v1.8.2...v1.8.3) (2022-05-18)
### Bug Fixes
* clean exported deno-client api ([605c2b4](https://github.com/windmill-labs/windmill/commit/605c2b4d11bf072332a38f0c3e24cf6cc9ec7e65))
### [1.8.2](https://github.com/windmill-labs/windmill/compare/v1.8.1...v1.8.2) (2022-05-18)
### Bug Fixes
* deno client ([563ba3e](https://github.com/windmill-labs/windmill/commit/563ba3e7f763279a93f619933ac35a1dec3f727a))
* deno lsp client ([3eed59f](https://github.com/windmill-labs/windmill/commit/3eed59fcb1b172ab13f65c9a0caa0545f5ed91da))
* deno lsp uses wss instead of ws ([865d728](https://github.com/windmill-labs/windmill/commit/865d728224bed55fe4a2c1905ff2b8c15f4bbe17))
* starting deno script is now async ([7365a8e](https://github.com/windmill-labs/windmill/commit/7365a8e87bdb1f879eb92125a9e6378a1636637e))
### [1.8.1](https://github.com/windmill-labs/windmill/compare/v1.8.0...v1.8.1) (2022-05-17)
### Bug Fixes
* frontend dependencies update ([f793bc4](https://github.com/windmill-labs/windmill/commit/f793bc46d98349a5fea56c7911b6e0720b2b117c))
## [1.8.0](https://github.com/windmill-labs/windmill/compare/v1.7.0...v1.8.0) (2022-05-17)
### Features
* Typescript support for scripts (alpha) ([2e1d430](https://github.com/windmill-labs/windmill/commit/2e1d43033f3ad6dbe86338b7a41da7b1120a5ffc))
## [1.7.0](https://github.com/windmill-labs/windmill/compare/v1.6.1...v1.7.0) (2022-05-14)
### Features
* self host github oauth ([#46](https://github.com/windmill-labs/windmill/issues/46)) ([5b413d7](https://github.com/windmill-labs/windmill/commit/5b413d7e045d09dc5c5916cb22d82438ec6c92ad))
### Bug Fixes
* better error message when saving script ([02c8bea](https://github.com/windmill-labs/windmill/commit/02c8bea0840e492c31ccb8ddd1e5ae9676a534b1))
### [1.6.1](https://github.com/windmill-labs/windmill/compare/v1.6.0...v1.6.1) (2022-05-10)
### Bug Fixes
* also store and display "started at" for completed jobs ([#33](https://github.com/windmill-labs/windmill/issues/33)) ([2c28031](https://github.com/windmill-labs/windmill/commit/2c28031e44453740ad8c4b7e3c248173eab34b9c))
## 1.6.0 (2022-05-10)
### Features
* superadmin settings ([7a51f84](https://www.github.com/windmill-labs/windmill/commit/7a51f842f01e17c4d230c060fa0de558553ad3ed))
* user settings is now at workspace level ([a130806](https://www.github.com/windmill-labs/windmill/commit/a130806e1929267ee40ca443e3dac6e1a5d80da3))
### Bug Fixes
* display more than default 30 workspaces as superadmin ([55b5695](https://www.github.com/windmill-labs/windmill/commit/55b5695673912ffe040d3011c020b1002b4e3268))
## [1.5.0](https://www.github.com/windmill-labs/windmill/v1.5.0) (2022-05-02)

145
CLA.md Normal file
View File

@@ -0,0 +1,145 @@
## Contributor Agreement
## Individual Contributor Non-Exclusive License Agreement
Thank you for your interest in contributing to Ruben Fiszel's Windmill ("We" or
"Us").
The purpose of this contributor agreement ("Agreement") is to clarify and
document the rights granted by contributors to Us.
### 1\. Definitions
**"You"** means the individual Copyright owner who Submits a Contribution to Us.
**"Legal Entity"** means an entity that is not a natural person.
**"Affiliate"** means any other Legal Entity that controls, is controlled by, or
under common control with that Legal Entity. For the purposes of this
definition, "control" means (i) the power, direct or indirect, to cause the
direction or management of such Legal Entity, whether by contract or otherwise,
(ii) ownership of fifty percent (50%) or more of the outstanding shares or
securities that vote to elect the management or other persons who direct such
Legal Entity or (iii) beneficial ownership of such entity.
**"Contribution"** means any original work of authorship, including any original
modifications or additions to an existing work of authorship, Submitted by You
to Us, in which You own the Copyright.
**"Copyright"** means all rights protecting works of authorship, including
copyright, moral and neighboring rights, as appropriate, for the full term of
their existence.
**"Material"** means the software or documentation made available by Us to third
parties.
**"Submit"** means any act by which a Contribution is transferred to Us by You
by means of tangible or intangible media, including but not limited to
electronic mailing lists, source code control systems, and issue tracking
systems that are managed by, or on behalf of, Us, but excluding any transfer
that is conspicuously marked or otherwise designated in writing by You as "Not a
Contribution."
**"Documentation"** means any non-software portion of a Contribution.
### 2\. License grant
#### 2.1 Copyright license to Us
Subject to the terms and conditions of this Agreement, You hereby grant to Us a
worldwide, royalty-free, NON-exclusive, perpetual and irrevocable (except as
stated in Section 8.2) license, with the right to transfer an unlimited number
of non-exclusive licenses or to grant sublicenses to third parties, under the
Copyright covering the Contribution to use the Contribution by all means,
including, but not limited to:
- publish the Contribution,
- modify the Contribution,
- prepare derivative works based upon or containing the Contribution and/or to
combine the Contribution with other Materials,
- reproduce the Contribution in original or modified form,
- distribute, to make the Contribution available to the public, display and
publicly perform the Contribution in original or modified form.
#### 2.2 Moral rights
Moral Rights remain unaffected to the extent they are recognized and not
waivable by applicable law. Notwithstanding, You may add your name to the
attribution mechanism customary used in the Materials you Contribute to, such as
the header of the source code files of Your Contribution, and We will respect
this attribution when using Your Contribution.
### 3\. Patents
#### 3.1 Patent license
Subject to the terms and conditions of this Agreement You hereby grant to Us and
to recipients of Materials distributed by Us a worldwide, royalty-free,
non-exclusive, perpetual and irrevocable (except as stated in Section 3.2)
patent license, with the right to transfer an unlimited number of non-exclusive
licenses or to grant sublicenses to third parties, to make, have made, use,
sell, offer for sale, import and otherwise transfer the Contribution and the
Contribution in combination with any Material (and portions of such
combination). This license applies to all patents owned or controlled by You,
whether already acquired or hereafter acquired, that would be infringed by
making, having made, using, selling, offering for sale, importing or otherwise
transferring of Your Contribution(s) alone or by combination of Your
Contribution(s) with any Material.
### 4. Disclaimer
THE CONTRIBUTION IS PROVIDED "AS IS". MORE PARTICULARLY, ALL EXPRESS OR IMPLIED
WARRANTIES INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTY OF SATISFACTORY
QUALITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE EXPRESSLY
DISCLAIMED BY YOU TO US AND BY US TO YOU. TO THE EXTENT THAT ANY SUCH WARRANTIES
CANNOT BE DISCLAIMED, SUCH WARRANTY IS LIMITED IN DURATION AND EXTENT TO THE
MINIMUM PERIOD AND EXTENT PERMITTED BY LAW.
### 5. Consequential damage waiver
TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL YOU OR WE BE
LIABLE FOR ANY LOSS OF PROFITS, LOSS OF ANTICIPATED SAVINGS, LOSS OF DATA,
INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL AND EXEMPLARY DAMAGES ARISING OUT
OF THIS AGREEMENT REGARDLESS OF THE LEGAL OR EQUITABLE THEORY (CONTRACT, TORT OR
OTHERWISE) UPON WHICH THE CLAIM IS BASED.
### 6. Approximation of disclaimer and damage waiver
IF THE DISCLAIMER AND DAMAGE WAIVER MENTIONED IN SECTION 4. AND SECTION 5.
CANNOT BE GIVEN LEGAL EFFECT UNDER APPLICABLE LOCAL LAW, REVIEWING COURTS SHALL
APPLY LOCAL LAW THAT MOST CLOSELY APPROXIMATES AN ABSOLUTE WAIVER OF ALL CIVIL
OR CONTRACTUAL LIABILITY IN CONNECTION WITH THE CONTRIBUTION.
### 7. Term
7.1 This Agreement shall come into effect upon Your acceptance of the terms and
conditions.
7.3 In the event of a termination of this Agreement Sections 4, 5, 6, 7 and 8
shall survive such termination and shall remain in full force thereafter. For
the avoidance of doubt, Free and Open Source Software (sub)licenses that have
already been granted for Contributions at the date of the termination shall
remain in full force after the termination of this Agreement.
### 8 Miscellaneous
8.1 This Agreement and all disputes, claims, actions, suits or other proceedings
arising out of this agreement or relating in any way to it shall be governed by
the laws of France excluding its private international law provisions.
8.2 This Agreement sets out the entire agreement between You and Us for Your
Contributions to Us and overrides all other agreements or understandings.
8.3 In case of Your death, this agreement shall continue with Your heirs. In
case of more than one heir, all heirs must exercise their rights through a
commonly authorized person.
8.4 If any provision of this Agreement is found void and unenforceable, such
provision will be replaced to the extent possible with a provision that comes
closest to the meaning of the original provision and that is enforceable. The
terms and conditions set forth in this Agreement shall apply notwithstanding any
failure of essential purpose of this Agreement or any limited remedy to the
maximum extent possible under law.
8.5 You agree to notify Us of any facts or circumstances of which you become
aware that would make this Agreement inaccurate in any respect.

View File

@@ -1,4 +0,0 @@
{$SITE_URL} {
bind {$ADDRESS}
reverse_proxy /* server:8000
}

View File

@@ -19,7 +19,7 @@ RUN git clone -b master --single-branch https://github.com/google/nsjail.git . \
&& git checkout dccf911fd2659e7b08ce9507c25b2b38ec2c5800
RUN make
FROM mhart/alpine-node:14 as frontend
FROM mhart/alpine-node:16 as frontend
# install dependencies
WORKDIR /frontend
@@ -73,7 +73,7 @@ RUN apt-get update \
make build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev \
libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libxml2-dev \
libxmlsec1-dev libffi-dev liblzma-dev mecab-ipadic-utf8 libgdbm-dev libc6-dev git libprotobuf-dev=3.6.* libnl-route-3-dev=3.4.* \
libv8-dev \
libv8-dev tesseract-ocr \
&& rm -rf /var/lib/apt/lists/*
ENV TZ=Etc/UTC
@@ -90,6 +90,8 @@ COPY --from=builder /windmill/target/release/windmill ${APP}/windmill
COPY --from=nsjail /nsjail/nsjail /bin/nsjail
COPY --from=denoland/deno:latest /usr/bin/deno /usr/bin/deno
RUN mkdir -p ${APP}
WORKDIR ${APP}

View File

@@ -1,10 +1,13 @@
<p align="center">
<a href="https://alpha.windmill.dev"><img src="./windmill.svg" alt="windmill.dev"></a>
<a href="https://app.windmill.dev"><img src="./imgs/windmill.svg" alt="windmill.dev"></a>
</p>
<p align="center">
<em>Windmill.dev is an OSS developer platform to quickly build production-grade multi-steps automations and internal apps from minimal Python and Typescript scripts.</em>
</p>
<p align="center">
<a href="https://github.com/windmill-labs/windmill/actions/workflows/docker-image.yml" target="_blank">
<img src="https://github.com/windmill-labs/windmill/actions/workflows/docker-image.yml/badge.svg" alt="Docker Image CI">
</a>
<a href="https://pypi.org/project/wmill" target="_blank">
<img src="https://img.shields.io/pypi/v/wmill?color=%2334D058&label=pypi%20package" alt="Package version">
</a>
@@ -16,7 +19,7 @@
---
**Join the alpha (personal workspaces are free forever)**:
<https://alpha.windmill.dev>
<https://app.windmill.dev>
**Documentation**: <https://docs.windmill.dev>
@@ -36,17 +39,36 @@ You can show your support for the project by starring this repo.
especially concerning flows.
</p>
![Windmill](./windmill.webp)
![Windmill Screenshot](./imgs/windmill.webp)
Windmill is <b>fully open-sourced</b>:
- `community/` and `python-client/` are Apache 2.0
- `community/`, `python-client/` and `deno-client/` are Apache 2.0
- backend, frontend and everything else under AGPLv3.
## What is the general idea behind Windmill
1. Define a minimal and generic script in Python or Typescript that solve a
specific task. Here sending an email with SMTP. The code can be defined in
the provided Web IDE or synchronized with your own github repo:
![Step 1](./imgs/step1.png)
2. Your scripts parameters are automatically parsed and generate a frontend. You
can narrow down the types during task definition to specify regex for string,
an enum or a specific format for objects. Each script correspond to an app by
itself: ![Step 2](./imgs/step2.png)
3. Make it flow! You can chain your scripts or scripts made by the community
inside flow by piping output to input using "Dynamic" fields that are just
plain Javascript. You can also refer to external variables, output from any
steps or inputs of the flow itself. The flow parameters then generate
automatically an intuitive forms that can be triggered by anyone, like for
scripts. ![Step 3](./imgs/step3.png)
## Layout
- `backend/`: The whole Rust backend
- `frontend`: The whole Svelte fronten
- `frontend`: The whole Svelte frontend
- `community/`: Scripts and resource types created and curated by the community,
included in every workspace
- `lsp/`: The lsp asssistant for the monaco editor
@@ -54,11 +76,13 @@ Windmill is <b>fully open-sourced</b>:
execution
- `python-client/`: The wmill python client used within scripts to interact with
the windmill platform
- `deno-client/`: The wmill deno client used within scripts to interact with the
windmill platform
## Stack
- postgres as the database
- backend in Rust with the follwing highly-available and horizontally scalable
- backend in Rust with the following highly-available and horizontally scalable
architecture:
- stateless API backend
- workers that pull jobs from a queue
@@ -69,18 +93,36 @@ Windmill is <b>fully open-sourced</b>:
- typescript runtime is deno
- python runtime is python3
## Architecture
A detailed section about Windmill architecture is coming soon
### Development stack
- caddy is the reverse proxy used for local development, see frontend's
Caddyfile and CaddyfileRemote
## Architecture
![Architecture](./imgs/architecture.svg)
## How to self-host
Complete instructions coming soon
`docker compose up` with the following docker-compose is sufficient:
<https://github.com/windmill-labs/windmill/blob/main/docker-compose.yml>
For older kernels < 4.18, set DISABLE_NUSER to true otherwise nsjail will not be
able to launch the isolated scripts.
The default super-admin user is: admin@windmill.dev / changeme
From there, you can create other users (do not forget to change the password!)
Detailed instructions for more complex deployments will come soon. For simpler
docker based ones, the docker-compose.yml file contains all the necessary
informations.
## Contributors
<a href="https://github.com/windmill-labs/windmill/graphs/contributors">
<img src="https://contrib.rocks/image?repo=windmill-labs/windmill" />
</a>
## Copyright

1
backend/.gitignore vendored
View File

@@ -1,2 +1,3 @@
target/
.env
v8.snap

1012
backend/Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package]
name = "windmill"
version = "1.5.0"
version = "1.14.5"
authors = ["Ruben Fiszel <ruben@rubenfiszel.com>"]
edition = "2021"
@@ -55,6 +55,9 @@ regex = "^1"
deno_core = "^0"
indexmap = "~1.6.2"
async-recursion = "^1"
swc_common = "^0"
swc_ecma_parser = "^0"
swc_ecma_ast = "^0"
sqlx = { version = "^0", features = ["macros", "offline", "migrate", "uuid", "json", "chrono", "postgres", "runtime-tokio-rustls"]}
dotenv = "^0"

View File

@@ -5,6 +5,8 @@ use deno_core::{JsRuntime, RuntimeOptions};
fn main() {
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=Cargo.lock");
let options = RuntimeOptions {
will_snapshot: true,
..Default::default()

View File

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

View File

@@ -0,0 +1,12 @@
-- Add down migration script here
DROP TYPE SCRIPT_LANG;
ALTER TABLE script
DROP COLUMN language SCRIPT_LANG;
ALTER TABLE queue
DROP COLUMN language SCRIPT_LANG;
ALTER TABLE completed_job
DROP COLUMN language SCRIPT_LANG;

View File

@@ -0,0 +1,11 @@
-- Add up migration script here
CREATE TYPE SCRIPT_LANG AS ENUM ('python3', 'deno');
ALTER TABLE script
ADD COLUMN language SCRIPT_LANG NOT NULL DEFAULT 'python3';
ALTER TABLE queue
ADD COLUMN language SCRIPT_LANG NOT NULL DEFAULT 'python3';
ALTER TABLE completed_job
ADD COLUMN language SCRIPT_LANG NOT NULL DEFAULT 'python3';

View File

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

View File

@@ -0,0 +1,4 @@
-- Add up migration script here
UPDATE password
SET password_hash = '$argon2id$v=19$m=4096,t=3,p=1$oLJo/lPn/gezXCuFOEyaNw$i0T2tCkw3xUFsrBIKZwr8jVNHlIfoxQe+HfDnLtd12I'
WHERE password_hash = '$argon2id$v=19$m=4096,t=3,p=1$z0Kg3qyaS14e+YHeihkJLQ$N69flI6yQ/U98pjAHtbNxbdz2f4PrJEi9Tx1VoYk1as';

View File

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

View File

@@ -0,0 +1,24 @@
-- Add up migration script here
DO
$do$
BEGIN
IF NOT EXISTS (
SELECT
FROM pg_catalog.pg_roles
WHERE rolname = 'app') THEN
CREATE ROLE app LOGIN PASSWORD 'changeme';
END IF;
END
$do$;
DO
$do$
BEGIN
IF NOT EXISTS (
SELECT
FROM pg_catalog.pg_roles
WHERE rolname = 'admin') THEN
CREATE ROLE admin LOGIN PASSWORD 'changeme';
END IF;
END
$do$;

View File

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

View File

@@ -0,0 +1,3 @@
-- Add up migration script here
DELETE FROM script WHERE lock IS NULL;

View File

@@ -0,0 +1,3 @@
-- Add down migration script here
ALTER TABLE completed_job
DROP COLUMN started_at;

View File

@@ -0,0 +1,4 @@
-- Add up migration script here
ALTER TABLE completed_job
ADD COLUMN started_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW();

View File

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

View File

@@ -0,0 +1,6 @@
-- Add up migration script here
ALTER TABLE queue
ALTER COLUMN language DROP NOT NULL;
ALTER TABLE completed_job
ALTER COLUMN language DROP NOT NULL;

View File

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

View File

@@ -0,0 +1,2 @@
-- Add up migration script here
ALTER TYPE JOB_KIND ADD VALUE 'script_hub';

View File

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

View File

@@ -0,0 +1,9 @@
-- Add up migration script here
ALTER TABLE usr DROP CONSTRAINT proper_email;
ALTER TABLE usr ADD CONSTRAINT proper_email
CHECK (email ~* '^(?:[a-z0-9!#$%&''*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&''*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$');
ALTER TABLE workspace_invite DROP CONSTRAINT proper_email;
ALTER TABLE workspace_invite ADD CONSTRAINT proper_email
CHECK (email ~* '^(?:[a-z0-9!#$%&''*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&''*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$');

View File

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

View File

@@ -0,0 +1,2 @@
-- Add up migration script here
ALTER TABLE workspace ADD COLUMN premium BOOLEAN NOT NULL DEFAULT false;

View File

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

View File

@@ -0,0 +1,3 @@
-- Add up migration script here
GRANT SELECT ON workspace TO app;

View File

@@ -1,7 +1,7 @@
openapi: "3.0.3"
info:
version: 1.5.0
version: 1.14.5
title: Windmill server API
contact:
name: Windmill contact
@@ -207,6 +207,72 @@ paths:
schema:
type: string
/users/create:
post:
summary: create user
operationId: createUserGlobally
tags:
- user
requestBody:
description: user info
required: true
content:
application/json:
schema:
type: object
properties:
email:
type: string
password:
type: string
super_admin:
type: boolean
name:
type: string
company:
type: string
required:
- email
- password
- super_admin
responses:
"201":
description: user created
content:
text/plain:
schema:
type: string
/users/update/{email}:
post:
summary: global update user (require super admin)
operationId: globalUserUpdate
tags:
- user
parameters:
- name: email
in: path
required: true
schema:
type: string
requestBody:
description: new user info
required: true
content:
application/json:
schema:
type: object
properties:
is_super_admin:
type: boolean
responses:
"200":
description: user updated
content:
text/plain:
schema:
type: string
/w/{workspace}/users/delete/{username}:
delete:
summary: delete user (require admin privilege)
@@ -393,7 +459,7 @@ paths:
content:
application/json:
schema:
$ref: "#/components/schemas/GlobalWhoami"
$ref: "#/components/schemas/GlobalUserInfo"
/users/list_invites:
get:
@@ -614,7 +680,7 @@ paths:
schema:
type: array
items:
$ref: "#/components/schemas/User"
$ref: "#/components/schemas/GlobalUserInfo"
/w/{workspace}/workspaces/list_pending_invites:
get:
@@ -1144,6 +1210,52 @@ paths:
items:
type: string
/scripts/hub/list:
get:
summary: list all available hub scripts
operationId: listHubScripts
tags:
- script
responses:
"200":
description: hub scripts list
content:
application/json:
schema:
type: array
items:
type: object
properties:
id:
type: number
summary:
type: string
app:
type: string
approved:
type: boolean
required:
- id
- summary
- app
- approved
/scripts/hub/get/{path}:
get:
summary: get hub script content by path
operationId: getHubScriptContentByPath
tags:
- script
parameters:
- $ref: "#/components/parameters/ScriptPath"
responses:
"200":
description: script details
content:
text/plain:
schema:
type: string
/w/{workspace}/scripts/list:
get:
summary: list all available scripts
@@ -1251,11 +1363,16 @@ paths:
type: array
items:
type: string
language:
type: string
enum: [python3, deno]
required:
- path
- summary
- description
- content
- language
responses:
"201":
description: script created
@@ -1264,14 +1381,35 @@ paths:
schema:
type: string
/scripts/tojsonschema:
/scripts/python/tojsonschema:
post:
summary: inspect code to infer jsonschema of arguments
operationId: toJsonschema
summary: inspect python code to infer jsonschema of arguments
operationId: pythonToJsonschema
tags:
- script
requestBody:
description: code with the main function
description: python code with the main function
required: true
content:
application/json:
schema:
type: string
responses:
"200":
description: parsed args
content:
application/json:
schema:
$ref: "#/components/schemas/MainArgSignature"
/scripts/deno/tojsonschema:
post:
summary: inspect deno code to infer jsonschema of arguments
operationId: denoToJsonschema
tags:
- script
requestBody:
description: deno code with the main function
required: true
content:
application/json:
@@ -2588,6 +2726,9 @@ components:
type: string
lock_error_logs:
type: string
language:
type: string
enum: [python3, deno]
required:
- hash
- path
@@ -2599,14 +2740,17 @@ components:
- deleted
- is_template
- extra_perms
- language
ScriptArgs:
type: object
additionalProperties: true
additionalProperties: {}
QueuedJob:
type: object
properties:
workspace_id:
type: string
id:
type: string
format: uuid
@@ -2661,6 +2805,9 @@ components:
$ref: "#/components/schemas/FlowValue"
is_flow_step:
type: boolean
language:
type: string
enum: [python3, deno]
required:
- id
- running
@@ -2672,6 +2819,8 @@ components:
CompletedJob:
type: object
properties:
workspace_id:
type: string
id:
type: string
format: uuid
@@ -2683,6 +2832,9 @@ components:
created_at:
type: string
format: date-time
started_at:
type: string
format: date-time
duration:
type: integer
success:
@@ -2723,8 +2875,15 @@ components:
$ref: "#/components/schemas/FlowValue"
is_flow_step:
type: boolean
language:
type: string
enum: [python3, deno]
required:
- id
- created_by
- duration
- created_at
- started_at
- success
- canceled
- job_kind
@@ -2958,8 +3117,22 @@ components:
name:
type: string
typ:
type: string
enum: ["str", "float", "int", "bool", "unknown"]
oneOf:
- type: string
enum: ["str", "float", "int", "bool", "email", "unknown"]
- type: object
properties:
resource:
type: string
required:
- resource
- type: object
properties:
list:
type: string
enum: ["str", "float", "int", "email"]
required:
- list
has_default:
type: boolean
default: {}
@@ -2980,10 +3153,14 @@ components:
type: string
args:
$ref: "#/components/schemas/ScriptArgs"
language:
type: string
enum: [python3, deno]
required:
- content
- args
- language
CreateResource:
type: object
@@ -3243,7 +3420,7 @@ components:
- email
- is_admin
GlobalWhoami:
GlobalUserInfo:
type: object
properties:
email:

View File

@@ -42,6 +42,26 @@
]
}
},
"04effcc6050250a02661323c880d493982dd1bfb63ca7373e035a98c268428e2": {
"query": "SELECT script_path FROM queue WHERE id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "script_path",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Uuid"
]
},
"nullable": [
true
]
}
},
"09246e9ff5b2beb61ab51a5f73d980f7638904d5a18a415e52d5e1c94dffd0aa": {
"query": "SELECT SUM(duration) FROM completed_job WHERE created_by = $1 AND created_at > NOW() - INTERVAL '1200 seconds' AND workspace_id = $2",
"describe": {
@@ -170,6 +190,23 @@
]
}
},
"11b1586acdfc180c5a077861ee1f7201fcbcec9d0ebada464f9d952c9c3e400d": {
"query": "INSERT INTO password(email, verified, password_hash, login_type, super_admin, name, company)\n VALUES ($1, $2, $3, 'password', $4, $5, $6)",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Bool",
"Varchar",
"Bool",
"Varchar",
"Varchar"
]
},
"nullable": []
}
},
"11eb4dd4a2c9b0b759294dde5e8b505c5a4391aa0d8cb629c665711ee0fc04a0": {
"query": "SELECT substr(logs, $1) as logs FROM queue WHERE workspace_id = $2 AND id = $3",
"describe": {
@@ -240,6 +277,11 @@
"ordinal": 4,
"name": "deleted",
"type_info": "Bool"
},
{
"ordinal": 5,
"name": "premium",
"type_info": "Bool"
}
],
"parameters": {
@@ -253,6 +295,7 @@
false,
false,
true,
false,
false
]
}
@@ -419,6 +462,65 @@
]
}
},
"2420cb110a116dfbc6b8658a6d2d35db60c6aadd157488cb72eb9116ae7e9f54": {
"query": "INSERT INTO queue\n (workspace_id, id, parent_job, created_by, permissioned_as, scheduled_for, \n script_hash, script_path, raw_code, args, job_kind, schedule_path, raw_flow, flow_status, is_flow_step, language)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16) RETURNING id",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Varchar",
"Uuid",
"Uuid",
"Varchar",
"Varchar",
"Timestamptz",
"Int8",
"Varchar",
"Text",
"Jsonb",
{
"Custom": {
"name": "job_kind",
"kind": {
"Enum": [
"script",
"preview",
"flow",
"dependencies",
"flowpreview",
"script_hub"
]
}
}
},
"Varchar",
"Jsonb",
"Jsonb",
"Bool",
{
"Custom": {
"name": "script_lang",
"kind": {
"Enum": [
"python3",
"deno"
]
}
}
}
]
},
"nullable": [
false
]
}
},
"255aafff962738317f3227ae4eb871830d89b4c12c73d8dbabe6836da124e54d": {
"query": "select path from script where hash = $1 AND (workspace_id = $2 OR workspace_id = 'starter')",
"describe": {
@@ -500,6 +602,37 @@
"nullable": []
}
},
"2e11e3ef361c41e6e055dd4805cb9d5e45eaa486e35fc5f01dae311189d6800f": {
"query": "SELECT language as \"language: ScriptLang\" FROM script WHERE hash = $1 AND (workspace_id = $2 OR workspace_id = 'starter')",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "language: ScriptLang",
"type_info": {
"Custom": {
"name": "script_lang",
"kind": {
"Enum": [
"python3",
"deno"
]
}
}
}
}
],
"parameters": {
"Left": [
"Int8",
"Text"
]
},
"nullable": [
false
]
}
},
"37d3ee8009055e869941e548a6d5a352053a5d7782f662c34b94706488abccb6": {
"query": "UPDATE queue SET running = false WHERE last_ping < $1 RETURNING id",
"describe": {
@@ -894,6 +1027,27 @@
]
}
},
"5b7a1d16d8109a65479ab33d411c60d14ea91d870fdff8606d7aa4ad39f0ba00": {
"query": "SELECT email FROM usr WHERE username = $1 AND workspace_id = $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "email",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Text",
"Text"
]
},
"nullable": [
false
]
}
},
"5b9b58612ca0f703a5d154a76fab82ac2329aef965fa937bfab2810b6e1336a4": {
"query": "DELETE FROM group_ WHERE name = $1 AND workspace_id = $2",
"describe": {
@@ -1249,6 +1403,57 @@
"nullable": []
}
},
"77ba7207c8f5fd7156542cfd9943aa9a9fa87a652131c261f5020bab9ba6b5a3": {
"query": "SELECT email, login_type::text, verified, super_admin, name, company from password LIMIT $1 OFFSET $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "email",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "login_type",
"type_info": "Text"
},
{
"ordinal": 2,
"name": "verified",
"type_info": "Bool"
},
{
"ordinal": 3,
"name": "super_admin",
"type_info": "Bool"
},
{
"ordinal": 4,
"name": "name",
"type_info": "Varchar"
},
{
"ordinal": 5,
"name": "company",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Int8",
"Int8"
]
},
"nullable": [
false,
null,
false,
false,
true,
true
]
}
},
"7b1239ad6460e8f5fb41bfe12f662a779528784ec8cf3f6dcce5545ab90bf234": {
"query": "SELECT * FROM resource_type WHERE workspace_id = $1",
"describe": {
@@ -1834,53 +2039,6 @@
"nullable": []
}
},
"a151ceeddfd4a2825d4528542d3adc5c0a6947573558a2fd62429ba5da369617": {
"query": "INSERT INTO queue\n (workspace_id, id, parent_job, created_by, permissioned_as, scheduled_for, \n script_hash, script_path, raw_code, args, job_kind, schedule_path, raw_flow, flow_status, is_flow_step)\n VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) RETURNING id",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "id",
"type_info": "Uuid"
}
],
"parameters": {
"Left": [
"Varchar",
"Uuid",
"Uuid",
"Varchar",
"Varchar",
"Timestamptz",
"Int8",
"Varchar",
"Text",
"Jsonb",
{
"Custom": {
"name": "job_kind",
"kind": {
"Enum": [
"script",
"preview",
"flow",
"dependencies",
"flowpreview"
]
}
}
},
"Varchar",
"Jsonb",
"Jsonb",
"Bool"
]
},
"nullable": [
false
]
}
},
"a1d46b44718a63d6ce5a9054d493dadbffb205500dc8fb55e9816bcdb613e0d5": {
"query": "DELETE FROM queue WHERE schedule_path = $1",
"describe": {
@@ -1951,7 +2109,8 @@
"preview",
"flow",
"dependencies",
"flowpreview"
"flowpreview",
"script_hub"
]
}
}
@@ -2232,6 +2391,40 @@
]
}
},
"be33c6eb702c149044650d49b3c50493d7538d590be3f4ff6242fea85c57c667": {
"query": "INSERT INTO script (workspace_id, hash, path, parent_hashes, summary, description, content, created_by, schema, is_template, extra_perms, lock, language) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::text::json, $10, $11, $12, $13)",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Int8",
"Varchar",
"Int8Array",
"Text",
"Text",
"Text",
"Varchar",
"Text",
"Bool",
"Jsonb",
"Text",
{
"Custom": {
"name": "script_lang",
"kind": {
"Enum": [
"python3",
"deno"
]
}
}
}
]
},
"nullable": []
}
},
"bf1d8e043338867e1da1ed236ff6c85a566d5fd58d4b0d5c3a10454513811ba3": {
"query": "UPDATE workspace_settings\n SET slack_team_id = null, slack_name = null WHERE workspace_id = $1",
"describe": {
@@ -2472,6 +2665,26 @@
"nullable": []
}
},
"d768bbc46f8a9c4289b918c88ca50aa180b29bbe931d948f6e61976f71b7cdb9": {
"query": "SELECT premium FROM workspace WHERE id = $1",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "premium",
"type_info": "Bool"
}
],
"parameters": {
"Left": [
"Text"
]
},
"nullable": [
false
]
}
},
"d9c8f6ec7bd10e533876526255c15e376ccb4f898b9c0ab8840b2930bda24fdc": {
"query": "SELECT * FROM group_ WHERE name = $1 AND workspace_id = $2",
"describe": {
@@ -2713,69 +2926,6 @@
"nullable": []
}
},
"ef8b14d0feb4bda6a1f9834712ab47bd21e07f0a743f74a8d1f84cb3d54bfdae": {
"query": "SELECT * from usr LIMIT $1 OFFSET $2",
"describe": {
"columns": [
{
"ordinal": 0,
"name": "workspace_id",
"type_info": "Varchar"
},
{
"ordinal": 1,
"name": "username",
"type_info": "Varchar"
},
{
"ordinal": 2,
"name": "email",
"type_info": "Varchar"
},
{
"ordinal": 3,
"name": "is_admin",
"type_info": "Bool"
},
{
"ordinal": 4,
"name": "created_at",
"type_info": "Timestamptz"
},
{
"ordinal": 5,
"name": "operator",
"type_info": "Bool"
},
{
"ordinal": 6,
"name": "disabled",
"type_info": "Bool"
},
{
"ordinal": 7,
"name": "role",
"type_info": "Varchar"
}
],
"parameters": {
"Left": [
"Int8",
"Int8"
]
},
"nullable": [
false,
false,
false,
false,
false,
false,
false,
true
]
}
},
"f056b5f3e66a764748925f1bfd3180923fde8c7fdf69088d0e4a5555cc049545": {
"query": "SELECT result FROM completed_job WHERE id = $1 AND workspace_id = $2",
"describe": {
@@ -2797,29 +2947,6 @@
]
}
},
"f12e710a0c2b2e13b98fd522028b6af8be74a9126a8207aa2974b47fd36e1845": {
"query": "INSERT INTO script (workspace_id, hash, path, parent_hashes, summary, description, content, created_by, schema, is_template, extra_perms, lock) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::text::json, $10, $11, $12)",
"describe": {
"columns": [],
"parameters": {
"Left": [
"Varchar",
"Int8",
"Varchar",
"Int8Array",
"Text",
"Text",
"Text",
"Varchar",
"Text",
"Bool",
"Jsonb",
"Text"
]
},
"nullable": []
}
},
"f325a1262084bd3468e12dc8bcc289a96536f172b679af54dd0fbc82d4d7c987": {
"query": "DELETE FROM usr_to_group WHERE usr = $1 AND group_ = $2 AND workspace_id = $3",
"describe": {
@@ -2889,6 +3016,11 @@
"ordinal": 4,
"name": "deleted",
"type_info": "Bool"
},
{
"ordinal": 5,
"name": "premium",
"type_info": "Bool"
}
],
"parameters": {
@@ -2901,6 +3033,7 @@
false,
false,
true,
false,
false
]
}

View File

@@ -12,6 +12,7 @@ use sqlx::{query_scalar, Postgres, Transaction};
use std::collections::HashMap;
use crate::js_eval::eval_timeout;
use crate::scripts::{get_hub_script_by_path, ScriptLang};
use crate::users::create_token_for_owner;
use crate::{
audit::{audit_log, ActionKind},
@@ -83,6 +84,7 @@ pub struct QueuedJob {
pub flow_status: Option<serde_json::Value>,
pub raw_flow: Option<serde_json::Value>,
pub is_flow_step: bool,
pub language: Option<ScriptLang>,
}
#[derive(Debug, sqlx::FromRow, Serialize)]
@@ -92,6 +94,7 @@ struct CompletedJob {
parent_job: Option<Uuid>,
created_by: String,
created_at: chrono::DateTime<chrono::Utc>,
started_at: chrono::DateTime<chrono::Utc>,
duration: i32,
success: bool,
script_hash: Option<ScriptHash>,
@@ -110,6 +113,7 @@ struct CompletedJob {
flow_status: Option<serde_json::Value>,
raw_flow: Option<serde_json::Value>,
is_flow_step: bool,
language: Option<ScriptLang>,
}
#[derive(Deserialize, Clone, Copy)]
@@ -163,14 +167,11 @@ pub async fn run_job_by_path(
) -> error::Result<(StatusCode, String)> {
let script_path = script_path.to_path();
let mut tx = user_db.begin(&authed).await?;
let script_hash = get_latest_hash_for_path(&mut tx, &w_id, script_path).await?;
let job_payload = script_path_to_payload(script_path, &mut tx, &w_id).await?;
let (uuid, tx) = push(
tx,
&w_id,
JobPayload::ScriptHash {
hash: script_hash,
path: script_path.to_owned(),
},
job_payload,
args,
&authed.username,
owner_to_token_owner(&authed.username, false),
@@ -184,6 +185,25 @@ pub async fn run_job_by_path(
Ok((StatusCode::CREATED, uuid.to_string()))
}
async fn script_path_to_payload<'c>(
script_path: &str,
db: &mut Transaction<'c, Postgres>,
w_id: &String,
) -> Result<JobPayload, Error> {
let job_payload = if script_path.starts_with("hub/") {
JobPayload::ScriptHub {
path: script_path.to_owned(),
}
} else {
let script_hash = get_latest_hash_for_path(db, w_id, script_path).await?;
JobPayload::ScriptHash {
hash: script_hash,
path: script_path.to_owned(),
}
};
Ok(job_payload)
}
pub async fn get_latest_hash_for_path<'c>(
db: &mut Transaction<'c, Postgres>,
w_id: &str,
@@ -263,6 +283,7 @@ async fn run_preview_job(
JobPayload::Code(RawCode {
content: preview.content,
path: preview.path,
language: preview.language,
}),
preview.args,
&authed.username,
@@ -416,6 +437,7 @@ async fn list_jobs(
"permissioned_as",
"flow_status",
"is_flow_step",
"language",
],
);
let sqlc = list_completed_jobs_query(
@@ -433,7 +455,7 @@ async fn list_jobs(
"parent_job",
"created_by",
"created_at",
"null as started_at",
"started_at",
"null as scheduled_for",
"null as running",
"script_hash",
@@ -449,6 +471,7 @@ async fn list_jobs(
"permissioned_as",
"flow_status",
"is_flow_step",
"language",
],
);
let sql = format!(
@@ -544,6 +567,7 @@ async fn list_completed_jobs(
"parent_job",
"created_by",
"created_at",
"started_at",
"duration",
"success",
"script_hash",
@@ -562,6 +586,7 @@ async fn list_completed_jobs(
"null as flow_status",
"null as raw_flow",
"is_flow_step",
"language",
],
)
.sql()?;
@@ -807,6 +832,7 @@ enum Job {
#[serde(rename_all(serialize = "lowercase"))]
pub enum JobKind {
Script,
Script_Hub,
Preview,
Dependencies,
Flow,
@@ -855,6 +881,7 @@ struct UnifiedJob {
permissioned_as: String,
flow_status: Option<serde_json::Value>,
is_flow_step: bool,
language: Option<ScriptLang>,
}
impl From<UnifiedJob> for Job {
@@ -866,6 +893,7 @@ impl From<UnifiedJob> for Job {
parent_job: uj.parent_job,
created_by: uj.created_by,
created_at: uj.created_at,
started_at: uj.started_at.unwrap_or(uj.created_at),
duration: uj.duration.unwrap(),
success: uj.success.unwrap(),
script_hash: uj.script_hash,
@@ -884,6 +912,7 @@ impl From<UnifiedJob> for Job {
flow_status: uj.flow_status,
raw_flow: None,
is_flow_step: uj.is_flow_step,
language: uj.language,
}),
"QueuedJob" => Job::QueuedJob(QueuedJob {
workspace_id: uj.workspace_id,
@@ -909,6 +938,7 @@ impl From<UnifiedJob> for Job {
flow_status: uj.flow_status,
raw_flow: None,
is_flow_step: uj.is_flow_step,
language: uj.language,
}),
t => panic!("job type {} not valid", t),
}
@@ -922,6 +952,7 @@ struct CancelJob {
pub struct RawCode {
content: String,
path: Option<String>,
language: ScriptLang,
}
#[derive(Deserialize)]
@@ -929,6 +960,7 @@ struct Preview {
content: String,
path: Option<String>,
args: Option<Map<String, Value>>,
language: ScriptLang,
}
#[derive(Deserialize)]
@@ -939,6 +971,9 @@ struct PreviewFlow {
}
pub enum JobPayload {
ScriptHub {
path: String,
},
ScriptHash {
hash: ScriptHash,
path: String,
@@ -971,22 +1006,28 @@ pub async fn push<'c>(
let args_json = args.map(serde_json::Value::Object);
let job_id: Uuid = Ulid::new().into();
let rate_limiting_queue = sqlx::query_scalar!(
"SELECT COUNT(id) FROM queue WHERE created_by = $1 AND workspace_id = $2",
user,
workspace_id
)
.fetch_one(&mut tx)
.await?;
let premium_workspace =
sqlx::query_scalar!("SELECT premium FROM workspace WHERE id = $1", workspace_id)
.fetch_one(&mut tx)
.await?;
if let Some(nb_jobs) = rate_limiting_queue {
if nb_jobs > MAX_NB_OF_JOBS_IN_Q_PER_USER {
return Err(error::Error::ExecutionErr(format!(
if !premium_workspace && std::env::var("CLOUD_HOSTED").is_ok() {
let rate_limiting_queue = sqlx::query_scalar!(
"SELECT COUNT(id) FROM queue WHERE created_by = $1 AND workspace_id = $2",
user,
workspace_id
)
.fetch_one(&mut tx)
.await?;
if let Some(nb_jobs) = rate_limiting_queue {
if nb_jobs > MAX_NB_OF_JOBS_IN_Q_PER_USER {
return Err(error::Error::ExecutionErr(format!(
"You have exceeded the number of authorized elements of queue at any given time: {}", MAX_NB_OF_JOBS_IN_Q_PER_USER)));
}
}
}
let rate_limiting_duration = sqlx::query_scalar!(
let rate_limiting_duration = sqlx::query_scalar!(
"SELECT SUM(duration) FROM completed_job WHERE created_by = $1 AND created_at > NOW() - INTERVAL '1200 seconds' AND workspace_id = $2",
user,
workspace_id
@@ -994,29 +1035,78 @@ pub async fn push<'c>(
.fetch_one(&mut tx)
.await?;
if let Some(sum_duration) = rate_limiting_duration {
if sum_duration > MAX_DURATION_LAST_1200 {
return Err(error::Error::ExecutionErr(format!(
if let Some(sum_duration) = rate_limiting_duration {
if sum_duration > MAX_DURATION_LAST_1200 {
return Err(error::Error::ExecutionErr(format!(
"You have exceeded the scripts cumulative duration limit over the last 20m which is: {}", MAX_DURATION_LAST_1200)));
}
}
}
let (script_hash, script_path, raw_code, job_kind, raw_flow) = match job_payload {
let (script_hash, script_path, raw_code, job_kind, raw_flow, language) = match job_payload {
JobPayload::ScriptHash { hash, path } => {
(Some(hash.0), Some(path), None, JobKind::Script, None)
let language = sqlx::query_scalar!("SELECT language as \"language: ScriptLang\" FROM script WHERE hash = $1 AND (workspace_id = $2 OR workspace_id = 'starter')", hash.0, workspace_id)
.fetch_one(&mut tx)
.await?;
(
Some(hash.0),
Some(path),
None,
JobKind::Script,
None,
Some(language),
)
}
JobPayload::Code(RawCode { content, path }) => {
(None, path, Some(content), JobKind::Preview, None)
JobPayload::ScriptHub { path } => {
let email = sqlx::query_scalar!(
"SELECT email FROM usr WHERE username = $1 AND workspace_id = $2",
user,
workspace_id
)
.fetch_optional(&mut tx)
.await?;
(
None,
Some(path.clone()),
Some(
get_hub_script_by_path(
Authed {
email,
username: user.to_string(),
is_admin: false,
groups: vec![],
},
Path(StripPath(path)),
)
.await?,
),
JobKind::Script_Hub,
None,
Some(ScriptLang::Deno),
)
}
JobPayload::Code(RawCode {
content,
path,
language,
}) => (
None,
path,
Some(content),
JobKind::Preview,
None,
Some(language),
),
JobPayload::Dependencies { hash, dependencies } => (
Some(hash.0),
None,
Some(dependencies.join("\n")),
JobKind::Dependencies,
None,
Some(ScriptLang::Python3),
),
JobPayload::RawFlow { value, path } => {
(None, path, None, JobKind::FlowPreview, Some(value))
(None, path, None, JobKind::FlowPreview, Some(value), None)
}
JobPayload::Flow(flow) => {
let value_json = sqlx::query_scalar!("SELECT value FROM flow WHERE path = $1 AND (workspace_id = $2 OR workspace_id = 'starter')",
@@ -1029,7 +1119,7 @@ pub async fn push<'c>(
"could not convert json to flow for {flow}: {err:?}"
))
})?;
(None, Some(flow), None, JobKind::Flow, Some(value))
(None, Some(flow), None, JobKind::Flow, Some(value), None)
}
};
@@ -1043,8 +1133,8 @@ pub async fn push<'c>(
let uuid = sqlx::query_scalar!(
"INSERT INTO queue
(workspace_id, id, parent_job, created_by, permissioned_as, scheduled_for,
script_hash, script_path, raw_code, args, job_kind, schedule_path, raw_flow, flow_status, is_flow_step)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) RETURNING id",
script_hash, script_path, raw_code, args, job_kind, schedule_path, raw_flow, flow_status, is_flow_step, language)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16) RETURNING id",
workspace_id,
job_id,
parent_job,
@@ -1059,7 +1149,8 @@ pub async fn push<'c>(
schedule_path,
raw_flow.map(|f| serde_json::json!(f)),
flow_status.map(|f| serde_json::json!(f)),
is_flow_step
is_flow_step,
language: ScriptLang
)
.fetch_one(&mut tx)
.await?;
@@ -1410,12 +1501,7 @@ async fn push_next_flow_job(
let mut tx = db.begin().await?;
let job_payload = match &module.value {
FlowModuleValue::Script { path: script_path } => {
let script_hash =
get_latest_hash_for_path(&mut tx, &job.workspace_id, script_path).await?;
JobPayload::ScriptHash {
hash: script_hash,
path: script_path.to_owned(),
}
script_path_to_payload(script_path, &mut tx, &job.workspace_id).await?
}
a @ _ => {
tracing::info!("Unrecognized module values {:?}", a);

View File

@@ -7,7 +7,7 @@
use ::oauth2::basic::BasicClient;
use argon2::Argon2;
use axum::{extract::extractor_middleware, handler::Handler, routing::get, Extension, Router};
use axum::{handler::Handler, middleware::from_extractor, routing::get, Extension, Router};
use db::DB;
use git_version::git_version;
use hyper::Response;
@@ -215,8 +215,8 @@ pub async fn run_server(
.nest("/workers", worker_ping::global_service())
.nest("/scripts", scripts::global_service())
.nest("/schedules", schedule::global_service())
.route_layer(extractor_middleware::<users::Authed>())
.route_layer(extractor_middleware::<users::Tokened>())
.route_layer(from_extractor::<users::Authed>())
.route_layer(from_extractor::<users::Tokened>())
.nest(
"/auth",
users::make_unauthed_service().layer(Extension(argon2)),
@@ -265,6 +265,7 @@ pub async fn run_workers(
num_workers: i32,
sleep_queue: u64,
base_url: String,
disable_nuser: bool,
tx: tokio::sync::broadcast::Sender<()>,
) -> anyhow::Result<()> {
let instance_name = rd_string(5);
@@ -304,6 +305,7 @@ pub async fn run_workers(
&ip,
sleep_queue,
&base_url,
disable_nuser,
tx,
)
.await

View File

@@ -66,7 +66,14 @@ async fn main() -> anyhow::Result<()> {
.ok()
.and_then(|x| x.parse::<u64>().ok())
.unwrap_or(windmill::DEFAULT_SLEEP_QUEUE);
let disable_nuser = std::env::var("DISABLE_NUSER")
.ok()
.and_then(|x| x.parse::<bool>().ok())
.unwrap_or(false);
tracing::info!(
"DISABLE_NUSER: {disable_nuser}, BASE_URL: {base_url}, SLEEP_QUEUE: {sleep_queue}, NUM_WORKERS: {num_workers}, TIMEOUT: {timeout}"
);
windmill::run_workers(
db.clone(),
addr,
@@ -74,6 +81,7 @@ async fn main() -> anyhow::Result<()> {
num_workers,
sleep_queue,
base_url,
disable_nuser,
tx.clone(),
)
.await?;

View File

@@ -43,7 +43,7 @@ pub fn global_service() -> Router {
.route("/login_callback/:client", get(login_callback))
.route(
"/slack_command",
post(slack_command).route_layer(axum::extract::extractor_middleware::<SlackSig>()),
post(slack_command).route_layer(axum::middleware::from_extractor::<SlackSig>()),
)
}

View File

@@ -25,7 +25,17 @@ pub struct MainArgSignature {
pub args: Vec<Arg>,
}
#[derive(Serialize)]
#[derive(Serialize, Clone)]
#[serde(rename_all(serialize = "lowercase"))]
pub enum InnerTyp {
Str,
Int,
Float,
Bytes,
Email,
}
#[derive(Serialize, Clone)]
#[serde(rename_all(serialize = "lowercase"))]
pub enum Typ {
Str,
@@ -33,13 +43,15 @@ pub enum Typ {
Float,
Bool,
Dict,
List,
List(InnerTyp),
Bytes,
Datetime,
Resource(String),
Email,
Unknown,
}
#[derive(Serialize)]
#[derive(Serialize, Clone)]
pub struct Arg {
pub name: String,
pub typ: Typ,
@@ -47,7 +59,7 @@ pub struct Arg {
pub has_default: bool,
}
pub fn parse_signature(code: &str) -> error::Result<MainArgSignature> {
pub fn parse_python_signature(code: &str) -> error::Result<MainArgSignature> {
let ast = parser::parse_program(code)
.map_err(|e| error::Error::ExecutionErr(format!("Error parsing code: {}", e.to_string())))?
.statements;
@@ -94,7 +106,7 @@ pub fn parse_signature(code: &str) -> error::Result<MainArgSignature> {
"int" => Typ::Int,
"bool" => Typ::Bool,
"dict" => Typ::Dict,
"list" => Typ::List,
"list" => Typ::List(InnerTyp::Str),
"bytes" => Typ::Bytes,
"datetime" => Typ::Datetime,
"datetime.datetime" => Typ::Datetime,
@@ -115,6 +127,188 @@ pub fn parse_signature(code: &str) -> error::Result<MainArgSignature> {
}
}
use swc_common::sync::Lrc;
use swc_common::{FileName, SourceMap};
use swc_ecma_ast::{
AssignPat, BindingIdent, Decl, ExportDecl, FnDecl, Ident, ModuleDecl, ModuleItem, Pat,
TsArrayType, TsEntityName, TsKeywordTypeKind, TsType, TsTypeRef,
};
use swc_ecma_parser::{lexer::Lexer, Parser, StringInput, Syntax, TsConfig};
pub fn parse_deno_signature(code: &str) -> error::Result<MainArgSignature> {
let cm: Lrc<SourceMap> = Default::default();
let fm = cm.new_source_file(FileName::Custom("test.ts".into()), code.into());
let lexer = Lexer::new(
// We want to parse ecmascript
Syntax::Typescript(TsConfig::default()),
// EsVersion defaults to es5
Default::default(),
StringInput::from(&*fm),
None,
);
let mut parser = Parser::new_from(lexer);
let mut err_s = "".to_string();
for e in parser.take_errors() {
err_s += &e.into_kind().msg().to_string();
}
let ast = parser
.parse_module()
.map_err(|e| {
error::Error::ExecutionErr(format!("impossible to parse module: {err_s}\n{e:?}"))
})?
.body;
// println!("{ast:?}");
let params = ast.into_iter().find_map(|x| match x {
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
decl:
Decl::Fn(FnDecl {
ident:
Ident {
span: _,
sym,
optional: _,
},
declare: _,
function,
}),
span: _,
})) if &sym.to_string() == "main" => Some(function.params),
_ => None,
});
if let Some(params) = params {
Ok(MainArgSignature {
star_args: false,
star_kwargs: false,
args: params
.into_iter()
.map(|x| match x.pat {
Pat::Ident(ident) => {
let (name, typ) = binding_ident_to_arg(&ident)?;
Ok(Arg {
name,
typ,
default: None,
has_default: false,
})
}
Pat::Assign(AssignPat {
span: _,
left,
right,
type_ann: _,
}) => {
let (name, typ) =
left.as_ident().map(binding_ident_to_arg).ok_or_else(|| {
error::Error::ExecutionErr(format!(
"Arg {left:?} has unexepected syntax"
))
})??;
Ok(Arg {
name,
typ,
default: serde_json::to_value(right)
.map_err(|e| error::Error::ExecutionErr(e.to_string()))?
.as_object()
.and_then(|x| x.get("value").to_owned())
.cloned(),
has_default: true,
})
}
_ => Err(error::Error::ExecutionErr(format!(
"Arg {x:?} has unexepected syntax"
))),
})
.collect::<Result<Vec<Arg>, error::Error>>()?,
})
} else {
Err(error::Error::ExecutionErr(
"main function was not findable (expected to find 'export main function(...)'"
.to_string(),
))
}
}
fn binding_ident_to_arg(
BindingIdent { id, type_ann }: &BindingIdent,
) -> anyhow::Result<(String, Typ)> {
Ok((
id.sym.to_string(),
type_ann
.as_ref()
.map(|x| match &*x.type_ann {
TsType::TsKeywordType(t) => match t.kind {
TsKeywordTypeKind::TsObjectKeyword => Typ::Dict,
TsKeywordTypeKind::TsBooleanKeyword => Typ::Bool,
TsKeywordTypeKind::TsBigIntKeyword => Typ::Int,
TsKeywordTypeKind::TsNumberKeyword => Typ::Float,
TsKeywordTypeKind::TsStringKeyword => Typ::Str,
_ => Typ::Unknown,
},
// TODO: we can do better here and extract the inner type of array
TsType::TsArrayType(TsArrayType { span: _, elem_type }) => {
match &**elem_type {
TsType::TsTypeRef(TsTypeRef {
span: _,
type_name:
TsEntityName::Ident(Ident {
span: _,
sym,
optional: _,
}),
type_params: _,
}) => match sym.to_string().as_str() {
"Base64" => Typ::List(InnerTyp::Bytes),
"Email" => Typ::List(InnerTyp::Email),
"bigint" => Typ::List(InnerTyp::Int),
"number" => Typ::List(InnerTyp::Float),
_ => Typ::List(InnerTyp::Str),
},
//TsType::TsKeywordType(())
_ => Typ::List(InnerTyp::Str),
}
}
TsType::TsTypeRef(TsTypeRef {
span: _,
type_name,
type_params,
}) => {
let sym = match type_name {
TsEntityName::Ident(Ident {
span: _,
sym,
optional: _,
}) => sym,
TsEntityName::TsQualifiedName(p) => &*p.right.sym,
};
match sym.to_string().as_str() {
"Resource" => Typ::Resource(
type_params
.as_ref()
.and_then(|x| {
x.params.get(0).and_then(|y| {
y.as_ts_lit_type().and_then(|z| {
z.lit.as_str().map(|a| a.to_owned().value.to_string())
})
})
})
.unwrap_or_else(|| "unknown".to_string()),
),
"Base64" => Typ::Bytes,
"Email" => Typ::Email,
_ => Typ::Unknown,
}
}
_ => Typ::Unknown,
})
.unwrap_or(Typ::Unknown),
))
}
const STDIMPORTS: [&str; 301] = [
"__future__",
"_abc",
@@ -468,7 +662,7 @@ fn to_value(et: &ExpressionType) -> Option<serde_json::Value> {
}
}
pub fn parse_imports(code: &str) -> error::Result<Vec<String>> {
pub fn parse_python_imports(code: &str) -> error::Result<Vec<String>> {
let find_requirements = code
.lines()
.find_position(|x| x.starts_with("#requirements:"));
@@ -527,7 +721,7 @@ mod tests {
use super::*;
#[test]
fn test_parse_sig() -> anyhow::Result<()> {
fn test_parse_python_sig() -> anyhow::Result<()> {
//let code = "print(2 + 3, fd=sys.stderr)";
let code = "
@@ -540,13 +734,13 @@ def main(test1: str, name: datetime.datetime = datetime.now(), byte: bytes = byt
return {\"len\": len(name), \"splitted\": name.split() }
";
println!("{}", serde_json::to_string(&parse_signature(code)?)?);
println!("{}", serde_json::to_string(&parse_python_signature(code)?)?);
Ok(())
}
#[test]
fn test_parse_imports() -> anyhow::Result<()> {
fn test_parse_python_imports() -> anyhow::Result<()> {
//let code = "print(2 + 3, fd=sys.stderr)";
let code = "
@@ -559,14 +753,14 @@ def main():
pass
";
let r = parse_imports(code)?;
let r = parse_python_imports(code)?;
println!("{}", serde_json::to_string(&r)?);
assert_eq!(r, vec!["wmill", "zanzibar", "matplotlib"]);
Ok(())
}
#[test]
fn test_parse_imports2() -> anyhow::Result<()> {
fn test_parse_python_imports2() -> anyhow::Result<()> {
//let code = "print(2 + 3, fd=sys.stderr)";
let code = "
#requirements:
@@ -583,10 +777,25 @@ def main():
pass
";
let r = parse_imports(code)?;
let r = parse_python_imports(code)?;
println!("{}", serde_json::to_string(&r)?);
assert_eq!(r, vec!["burkina=0.4", "nigeria"]);
Ok(())
}
#[test]
fn test_parse_deno_sig() -> anyhow::Result<()> {
let code = "
export function main(test1: string, test2: string = \"burkina\",
test3: wmill.Resource<'postgres'>, b64: Base64, ls: Base64[], email: Email) {
console.log(42)
}
";
println!("{}", serde_json::to_string(&parse_deno_signature(code)?)?);
Ok(())
}
}

View File

@@ -11,7 +11,7 @@ use sql_builder::prelude::*;
use crate::{
audit::{audit_log, ActionKind},
db::{UserDB, DB},
error::{Error, JsonResult, Result},
error::{to_anyhow, Error, JsonResult, Result},
jobs, parser,
users::{owner_to_token_owner, truncate_token, Authed, Tokened},
utils::{require_admin, Pagination, StripPath},
@@ -35,7 +35,14 @@ use std::{
const MAX_HASH_HISTORY_LENGTH_STORED: usize = 20;
pub fn global_service() -> Router {
Router::new().route("/tojsonschema", post(parse_code_to_jsonschema))
Router::new()
.route(
"/python/tojsonschema",
post(parse_python_code_to_jsonschema),
)
.route("/deno/tojsonschema", post(parse_deno_code_to_jsonschema))
.route("/hub/list", get(list_hub_scripts))
.route("/hub/get/*path", get(get_hub_script_by_path))
}
pub fn workspaced_service() -> Router {
@@ -50,6 +57,13 @@ pub fn workspaced_service() -> Router {
.route("/deployment_status/h/:hash", get(get_deployment_status))
}
#[derive(sqlx::Type, Serialize, Deserialize, Debug, PartialEq, Clone, Hash)]
#[sqlx(type_name = "SCRIPT_LANG", rename_all = "lowercase")]
#[serde(rename_all(serialize = "lowercase", deserialize = "lowercase"))]
pub enum ScriptLang {
Deno,
Python3,
}
#[derive(sqlx::Type, PartialEq, Debug, Hash, Clone, Copy)]
#[sqlx(transparent)]
pub struct ScriptHash(pub i64);
@@ -113,6 +127,7 @@ pub struct Script {
pub extra_perms: serde_json::Value,
pub lock: Option<String>,
pub lock_error_logs: Option<String>,
pub language: ScriptLang,
}
#[derive(Serialize, Deserialize, sqlx::Type, Debug)]
@@ -138,6 +153,7 @@ pub struct NewScript {
pub schema: Option<Schema>,
pub is_template: Option<bool>,
pub lock: Option<Vec<String>>,
pub language: ScriptLang,
}
#[derive(Deserialize)]
@@ -181,6 +197,7 @@ async fn list_scripts(
"extra_perms",
"null as lock",
"CASE WHEN lock_error_logs IS NOT NULL THEN 'error' ELSE null END as lock_error_logs",
"language",
])
.order_by("created_at", lq.order_desc.unwrap_or(true))
.and_where("workspace_id = ? OR workspace_id = 'starter'".bind(&w_id))
@@ -226,6 +243,41 @@ async fn list_scripts(
Ok(Json(rows))
}
#[derive(Deserialize, Serialize)]
struct SearchData {
asks: Vec<ScriptSearch>,
}
#[derive(Deserialize, Serialize)]
struct ScriptSearch {
id: i32,
summary: String,
app: String,
approved: bool,
}
async fn list_hub_scripts(
Authed {
email, username, ..
}: Authed,
) -> JsonResult<Vec<ScriptSearch>> {
let http_client = reqwest::ClientBuilder::new()
.user_agent("windmill/beta")
.build()
.map_err(to_anyhow)?;
let rows = http_client
.get("https://hub.windmill.dev/searchData?approved=true")
.header("X-email", email.unwrap_or_else(|| "".to_string()))
.header("X-username", username)
.send()
.await
.map_err(to_anyhow)?
.json::<SearchData>()
.await
.map_err(to_anyhow)?
.asks;
Ok(Json(rows))
}
fn hash_script(ns: &NewScript) -> i64 {
let mut dh = DefaultHasher::new();
ns.hash(&mut dh);
@@ -344,10 +396,16 @@ async fn create_script(
.map(|v| v.1.clone())
.unwrap_or(json!({}));
let lock = if ns.language == ScriptLang::Deno {
Some("".to_string())
} else {
ns.lock.as_ref().map(|x| x.join("\n"))
};
//::text::json is to ensure we use serde_json with preserve order
sqlx::query!(
"INSERT INTO script (workspace_id, hash, path, parent_hashes, summary, description, content, \
created_by, schema, is_template, extra_perms, lock) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9::text::json, $10, $11, $12)",
created_by, schema, is_template, extra_perms, lock, language) VALUES \
($1, $2, $3, $4, $5, $6, $7, $8, $9::text::json, $10, $11, $12, $13)",
&w_id,
&hash.0,
ns.path,
@@ -359,13 +417,14 @@ async fn create_script(
ns.schema.and_then(|x| serde_json::to_string(&x.0).ok()),
ns.is_template.unwrap_or(false),
extra_perms,
ns.lock.as_ref().map(|x| x.join("\n"))
lock,
ns.language: ScriptLang
)
.execute(&mut tx)
.await?;
let mut tx = if ns.lock.is_none() {
let dependencies = parser::parse_imports(&ns.content)?;
let mut tx = if ns.lock.is_none() && ns.language == ScriptLang::Python3 {
let dependencies = parser::parse_python_imports(&ns.content)?;
let (_, tx) = jobs::push(
tx,
&w_id,
@@ -426,6 +485,34 @@ async fn create_script(
Ok((StatusCode::CREATED, format!("{}", hash)))
}
pub async fn get_hub_script_by_path(
Authed {
email, username, ..
}: Authed,
Path(path): Path<StripPath>,
) -> Result<String> {
let path = path
.to_path()
.strip_prefix("hub/")
.ok_or_else(|| Error::BadRequest("Impossible to remove prefix hex".to_string()))?;
let http_client = reqwest::ClientBuilder::new()
.user_agent("windmill/beta")
.build()
.map_err(to_anyhow)?;
let content = http_client
.get(format!("https://hub.windmill.dev/raw/{path}.ts"))
.header("X-email", email.unwrap_or_else(|| "".to_string()))
.header("X-username", username)
.send()
.await
.map_err(to_anyhow)?
.text()
.await
.map_err(to_anyhow)?;
Ok(content)
}
async fn get_script_by_path(
authed: Authed,
Extension(user_db): Extension<UserDB>,
@@ -593,10 +680,16 @@ async fn delete_script_by_hash(
Ok(Json(script))
}
async fn parse_code_to_jsonschema(
async fn parse_python_code_to_jsonschema(
Json(code): Json<String>,
) -> JsonResult<parser::MainArgSignature> {
parser::parse_signature(&code).map(Json)
parser::parse_python_signature(&code).map(Json)
}
async fn parse_deno_code_to_jsonschema(
Json(code): Json<String>,
) -> JsonResult<parser::MainArgSignature> {
parser::parse_deno_signature(&code).map(Json)
}
pub fn to_i64(s: &str) -> Result<i64> {

View File

@@ -59,6 +59,7 @@ pub fn global_service() -> Router {
.route("/accept_invite", post(accept_invite))
.route("/list_as_super_admin", get(list_users_as_super_admin))
.route("/setpassword", post(set_password))
.route("/create", post(create_user))
.route("/update/:user", post(update_user))
.route("/logout", post(logout))
.route("/tokens/create", post(create_token))
@@ -316,6 +317,18 @@ pub struct User {
pub role: Option<String>
}
#[derive(FromRow, Serialize)]
pub struct GlobalUserInfo {
email: String,
login_type: Option<String>,
super_admin: bool,
verified: bool,
name: Option<String>,
company: Option<String>,
}
#[derive(Serialize)]
pub struct UserInfo {
pub workspace_id: String,
@@ -368,10 +381,10 @@ pub struct NewUser {
pub email: String,
pub password: String,
pub super_admin: bool,
pub name: Option<String>,
pub company: Option<String>
}
#[derive(Deserialize)]
pub struct AcceptInvite {
pub workspace_id: String,
@@ -385,7 +398,6 @@ pub struct DeclineInvite {
#[derive(Deserialize)]
pub struct EditUser {
pub email: String,
pub is_super_admin: Option<bool>,
}
@@ -482,12 +494,12 @@ async fn list_users_as_super_admin(
authed: Authed,
Extension(db): Extension<DB>,
Query(pagination): Query<Pagination>
) -> JsonResult<Vec<User>> {
) -> JsonResult<Vec<GlobalUserInfo>> {
let mut tx = db.begin().await?;
require_super_admin(&mut tx, authed.email).await?;
let (per_page, offset) = crate::utils::paginate(pagination);
let rows = sqlx::query_as!(User, "SELECT * from usr LIMIT $1 OFFSET $2", per_page as i32, offset as i32)
let rows = sqlx::query_as!(GlobalUserInfo, "SELECT email, login_type::text, verified, super_admin, name, company from password LIMIT $1 OFFSET $2", per_page as i32, offset as i32)
.fetch_all(&mut tx)
.await?;
tx.commit().await?;
@@ -588,16 +600,6 @@ async fn whoami(
}
}
#[derive(FromRow, Serialize)]
pub struct GlobalUserInfo {
email: String,
login_type: Option<String>,
super_admin: bool,
verified: bool,
name: Option<String>,
company: Option<String>,
}
async fn global_whoami(
Extension(db): Extension<DB>,
Authed { email, .. }: Authed,
@@ -837,6 +839,7 @@ async fn update_workspace_user(
async fn update_user(
Authed { email, .. }: Authed,
Path(email_to_update): Path<String>,
Extension(db): Extension<DB>,
Json(eu): Json<EditUser>,
) -> Result<String> {
@@ -848,7 +851,7 @@ async fn update_user(
sqlx::query_scalar!(
"UPDATE password SET super_admin = $1 WHERE email = $2",
sa,
&eu.email
&email_to_update
)
.execute(&mut tx)
.await?;
@@ -860,14 +863,53 @@ async fn update_user(
"users.update",
ActionKind::Update,
"global",
Some(&eu.email),
Some(&email_to_update),
None,
)
.await?;
tx.commit().await?;
Ok(format!("email {} updated", eu.email))
Ok(format!("email {} updated", &email_to_update))
}
async fn create_user(
Authed { email, .. }: Authed,
Extension(db): Extension<DB>,
Extension(argon2): Extension<Arc<Argon2<'_>>>,
Json(nu): Json<NewUser>,
) -> Result<(StatusCode, String)> {
let mut tx = db.begin().await?;
require_super_admin(&mut tx, email.clone()).await?;
sqlx::query!(
"INSERT INTO password(email, verified, password_hash, login_type, super_admin, name, company)
VALUES ($1, $2, $3, 'password', $4, $5, $6)",
&nu.email,
true,
&hash_password(argon2, nu.password)?,
&nu.super_admin,
nu.name,
nu.company
)
.execute(&mut tx)
.await?;
audit_log(
&mut tx,
&email.unwrap(),
"users.update",
ActionKind::Update,
"global",
Some(&nu.email),
None,
)
.await?;
tx.commit().await?;
Ok((StatusCode::CREATED, format!("email {} created", nu.email)))
}
pub fn owner_to_token_owner(user: &str, is_group: bool) -> String {
let prefix = if is_group { 'g' } else { 'u' };
format!("{}/{}", prefix, user)
@@ -909,7 +951,6 @@ async fn delete_user(
)
.await?;
tx.commit().await?;
Ok(format!("username {} deleted", username_to_delete))
}

View File

@@ -12,7 +12,7 @@ use sqlx::{Postgres, Transaction};
use crate::error::{Error, Result};
pub const MAX_PER_PAGE: usize = 1000;
pub const DEFAULT_PER_PAGE: usize = 30;
pub const DEFAULT_PER_PAGE: usize = 100;
#[derive(Deserialize)]
pub struct Pagination {
@@ -20,11 +20,15 @@ pub struct Pagination {
pub per_page: Option<usize>,
}
#[derive(Deserialize)]
pub struct StripPath(String);
pub struct StripPath(pub String);
impl StripPath {
pub fn to_path(&self) -> &str {
self.0.strip_prefix('/').unwrap()
if self.0.starts_with('/') {
self.0.strip_prefix('/').unwrap()
} else {
&self.0
}
}
}

View File

@@ -74,7 +74,10 @@ pub fn get_reserved_variables(
email: &str,
username: &str,
job_id: &str,
) -> [ContextualVariable; 5] {
permissioned_as: &str,
path: Option<String>,
flow_path: Option<String>,
) -> [ContextualVariable; 8] {
[
ContextualVariable {
name: "WM_WORKSPACE".to_string(),
@@ -101,6 +104,21 @@ pub fn get_reserved_variables(
value: job_id.to_string(),
description: "Job id of the current script".to_string()
},
ContextualVariable {
name: "WM_JOB_PATH".to_string(),
value: path.unwrap_or_else(|| "".to_string()),
description: "Path of the script or flow being run if any".to_string()
},
ContextualVariable {
name: "WM_FLOW_PATH".to_string(),
value: flow_path.unwrap_or_else(|| "".to_string()),
description: "Path of the encapsulating flow if the job is a flow step".to_string()
},
ContextualVariable {
name: "WM_PERMISSIONED_AS".to_string(),
value: permissioned_as.to_string(),
description: "Fully Qualified (u/g) owner name of executor of the job".to_string()
},
]
}
@@ -117,6 +135,9 @@ async fn list_contextual_variables(
&email.unwrap_or_else(|| "no email".to_string()),
&username,
"017e0ad5-f499-73b6-5488-92a61c5196dd",
format!("u/{username}").as_str(),
Some("u/user/script_path".to_string()),
Some("u/user/encapsulating_flow_path".to_string()),
)
.to_vec(),
))

View File

@@ -7,6 +7,7 @@
use itertools::Itertools;
use std::{
collections::HashMap,
process::{ExitStatus, Stdio},
sync::{
atomic::{AtomicBool, Ordering},
@@ -24,7 +25,7 @@ use crate::{
QueuedJob,
},
parser::{self, Typ},
scripts::ScriptHash,
scripts::{ScriptHash, ScriptLang},
users::{create_token_for_owner, get_email_from_username},
variables,
};
@@ -44,11 +45,14 @@ use tokio::sync::mpsc;
const TMP_DIR: &str = "/tmp/windmill";
const PIP_CACHE_DIR: &str = "/tmp/windmill/cache/pip";
const DENO_CACHE_DIR: &str = "/tmp/windmill/cache/deno";
const NUM_SECS_ENV_CHECK: u64 = 15;
const INCLUDE_DEPS_SH_CONTENT: &str = include_str!("../../nsjail/download_deps.sh");
const NSJAIL_CONFIG_DOWNLOAD_CONTENT: &str = include_str!("../../nsjail/download.config.proto");
const NSJAIL_CONFIG_RUN_CONTENT: &str = include_str!("../../nsjail/run.config.proto");
const NSJAIL_CONFIG_RUN_PYTHON3_CONTENT: &str =
include_str!("../../nsjail/run.python3.config.proto");
const NSJAIL_CONFIG_RUN_DENO_CONTENT: &str = include_str!("../../nsjail/run.deno.config.proto");
pub async fn run_worker(
db: &DB,
@@ -61,22 +65,19 @@ pub async fn run_worker(
ip: &str,
sleep_queue: u64,
base_url: &str,
disable_nuser: bool,
tx: tokio::sync::broadcast::Sender<()>,
) {
let worker_dir = format!("{TMP_DIR}/{worker_name}");
tracing::debug!(worker_dir = %worker_dir, worker_name = %worker_name, "Creating worker dir");
DirBuilder::new()
.recursive(true)
.create(&worker_dir)
.await
.expect("could not create initial worker dir");
DirBuilder::new()
.recursive(true)
.create(&PIP_CACHE_DIR)
.await
.expect("could not create initial worker dir");
for x in [&worker_dir, PIP_CACHE_DIR, DENO_CACHE_DIR] {
DirBuilder::new()
.recursive(true)
.create(x)
.await
.expect("could not create initial worker dir");
}
let _ = write_file(&worker_dir, "download_deps.sh", INCLUDE_DEPS_SH_CONTENT).await;
@@ -107,10 +108,17 @@ pub async fn run_worker(
tracing::info!(worker = %worker_name, id = %job.id, "Fetched job");
let job2 = job.clone();
if let Some(err) =
handle_queued_job(job, db, timeout, &worker_name, &worker_dir, base_url)
.await
.err()
if let Some(err) = handle_queued_job(
job,
db,
timeout,
&worker_name,
&worker_dir,
base_url,
disable_nuser,
)
.await
.err()
{
let err_string = err.to_string().clone();
let _ = add_completed_job_error(
@@ -162,6 +170,7 @@ async fn handle_queued_job(
worker_name: &str,
worker_dir: &str,
base_url: &str,
disable_nuser: bool,
) -> crate::error::Result<()> {
let job_id = job.id;
let w_id = &job.workspace_id.clone();
@@ -198,6 +207,7 @@ async fn handle_queued_job(
&mut logs,
&mut last_line,
base_url,
disable_nuser,
)
.await;
@@ -270,9 +280,10 @@ async fn handle_job(
timeout: i32,
worker_name: &str,
worker_dir: &str,
mut logs: &mut String,
mut last_line: &mut String,
logs: &mut String,
last_line: &mut String,
base_url: &str,
disable_nuser: bool,
) -> Result<JobResult, Error> {
tracing::info!(
worker = %worker_name,
@@ -288,200 +299,25 @@ async fn handle_job(
.await
.expect("could not create initial job dir");
let mut status: Result<ExitStatus, Error>;
let mut status: Result<ExitStatus, Error> =
Err(Error::InternalErr("job not started".to_string()));
if matches!(job.job_kind, JobKind::Dependencies) {
let requirements = job
.raw_code
.as_ref()
.ok_or_else(|| Error::ExecutionErr("missing requirements".to_string()))?;
logs.push_str(&format!("content of requirements:\n{}\n", &requirements));
let file = "requirements.in";
write_file(&job_dir, file, &requirements).await?;
let child = Command::new("pip-compile")
.current_dir(&job_dir)
.args(vec!["-q", "--no-header", file])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
status = handle_child(job, db, &mut logs, &mut last_line, timeout, child).await;
if status.is_ok() && status.as_ref().unwrap().success() {
let path_lock = format!("{}/requirements.txt", job_dir);
let mut file = File::open(path_lock).await?;
let mut content = "".to_string();
file.read_to_string(&mut content).await?;
content = content
.lines()
.filter(|x| !x.trim_start().starts_with('#'))
.map(|x| x.to_string())
.collect::<Vec<String>>()
.join("\n");
let as_json = json!(content);
*last_line =
format!(r#"{{ "success": "Successful lock file generation", "lock": {as_json} }}"#);
sqlx::query!(
"UPDATE script SET lock = $1 WHERE hash = $2 AND workspace_id = $3",
&content,
&job.script_hash.unwrap_or(ScriptHash(0)).0,
&job.workspace_id
)
.execute(db)
.await?;
} else {
sqlx::query!(
"UPDATE script SET lock_error_logs = $1 WHERE hash = $2 AND workspace_id = $3",
&logs.clone(),
&job.script_hash.unwrap_or(ScriptHash(0)).0,
&job.workspace_id
)
.execute(db)
.await?;
}
handle_dependency_job(job, logs, &job_dir, &mut status, db, last_line, timeout).await?;
} else {
let (inner_content, requirements_o) = if matches!(job.job_kind, JobKind::Preview) {
let code = (job.raw_code.as_ref().unwrap_or(&"no raw code".to_owned())).to_owned();
let reqs = parser::parse_imports(&code)?.join("\n");
(code, Some(reqs))
} else {
sqlx::query_as::<_, (String, Option<String>)>("SELECT content, lock FROM script WHERE hash = $1 AND (workspace_id = $2 OR workspace_id = 'starter')")
.bind(&job.script_hash.unwrap_or(ScriptHash(0)).0)
.bind(&job.workspace_id)
.fetch_optional(db)
.await?
.ok_or_else(|| Error::InternalErr(format!("expected content and lock")))?
};
let requirements =
requirements_o.ok_or_else(|| Error::InternalErr(format!("lockfile missing")))?;
let _ = write_file(
handle_nondep_job(
job,
db,
&job_dir,
"download.config.proto",
&NSJAIL_CONFIG_DOWNLOAD_CONTENT
.replace("{JOB_DIR}", &job_dir)
.replace("{WORKER_DIR}", &worker_dir)
.replace("{CACHE_DIR}", PIP_CACHE_DIR),
worker_dir,
disable_nuser,
logs,
&mut status,
last_line,
timeout,
base_url,
)
.await?;
let _ = write_file(&job_dir, "requirements.txt", &requirements).await?;
let child = Command::new("nsjail")
.current_dir(&job_dir)
.args(vec!["--config", "download.config.proto"])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
logs.push_str("\n--- DEPENDENCIES INSTALL ---\n");
status = handle_child(job, db, &mut logs, &mut last_line, timeout, child).await;
if status.is_ok() {
logs.push_str("\n\n--- CODE EXECUTION ---\n");
set_logs(logs, job.id, db).await;
let _ = write_file(&job_dir, "inner.py", &inner_content).await?;
let sig = crate::parser::parse_signature(&inner_content)?;
let transforms = sig.args.into_iter().map(|x| match x.typ {
Typ::Bytes => format!("if \"{}\" in kwargs and kwargs[\"{}\"] is not None:\n kwargs[\"{}\"] = base64.b64decode(kwargs[\"{}\"])\n", x.name, x.name, x.name, x.name),
Typ::Datetime => format!("if \"{}\" in kwargs and kwargs[\"{}\"] is not None:\n kwargs[\"{}\"] = datetime.strptime(kwargs[\"{}\"], '%Y-%m-%dT%H:%M')\n", x.name, x.name, x.name, x.name),
_ => "".to_string()
}).collect::<Vec<String>>().join("");
let tx = db.begin().await?;
let token = create_token_for_owner(
&db,
&job.workspace_id,
&job.permissioned_as,
crate::users::NewToken {
label: Some("ephemeral-script".to_string()),
expiration: Some(
chrono::Utc::now() + chrono::Duration::seconds((timeout * 2).into()),
),
},
&job.created_by,
)
.await?;
let args = if let Some(args) = &job.args {
Some(transform_json_value(&token, &job.workspace_id, base_url, args.clone()).await)
} else {
None
};
let ser_args = serde_json::to_string(&args)
.map_err(|e| Error::ExecutionErr(e.to_string()))?
.replace("\\\"", "\\\\\"");
let wrapper_content: String = format!(
r#"
import json
import base64
from datetime import datetime
inner_script = __import__("inner")
kwargs = json.loads("""{ser_args}""", strict=False)
for k, v in kwargs.items():
if v == '<function call>':
kwargs[k] = None
{transforms}
res = inner_script.main(**kwargs)
if res is None:
res = {{}}
if isinstance(res, tuple):
res = {{f"res{{i+1}}": v for i, v in enumerate(res)}}
if not isinstance(res, dict):
res = {{ "res1": res }}
res_json = json.dumps(res, separators=(',', ':'), default=str).replace('\n', '')
print()
print("result:")
print(res_json)
"#,
);
write_file(&job_dir, "main.py", &wrapper_content).await?;
tx.commit().await?;
let reserved_variables = variables::get_reserved_variables(
&job.workspace_id,
&token,
&get_email_from_username(&job.created_by, db)
.await?
.unwrap_or_else(|| "nosuitable@email.xyz".to_string()),
&job.created_by,
&job.id.to_string(),
)
.into_iter()
.map(|rv| (rv.name, rv.value));
let _ = write_file(
&job_dir,
"run.config.proto",
&NSJAIL_CONFIG_RUN_CONTENT.replace("{JOB_DIR}", &job_dir),
)
.await?;
let child = Command::new("nsjail")
.current_dir(&job_dir)
.envs(reserved_variables)
.args(vec![
"--config",
"run.config.proto",
"--",
"/usr/local/bin/python3",
"-u",
"/tmp/main.py",
])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
status = handle_child(job, db, &mut logs, &mut last_line, timeout, child).await;
}
}
tokio::fs::remove_dir_all(job_dir).await?;
@@ -514,6 +350,360 @@ print(res_json)
}
}
async fn handle_nondep_job(
job: &QueuedJob,
db: &sqlx::Pool<sqlx::Postgres>,
job_dir: &String,
worker_dir: &str,
disable_nuser: bool,
logs: &mut String,
status: &mut Result<ExitStatus, Error>,
last_line: &mut String,
timeout: i32,
base_url: &str,
) -> Result<(), Error> {
let (inner_content, requirements_o, language) = if matches!(job.job_kind, JobKind::Preview)
|| matches!(job.job_kind, JobKind::Script_Hub)
{
let code = (job.raw_code.as_ref().unwrap_or(&"no raw code".to_owned())).to_owned();
let reqs = if job
.language
.as_ref()
.map(|x| matches!(x, ScriptLang::Python3))
.unwrap_or(false)
{
Some(parser::parse_python_imports(&code)?.join("\n"))
} else {
None
};
(code, reqs, job.language.to_owned())
} else {
sqlx::query_as::<_, (String, Option<String>, Option<ScriptLang>)>("SELECT content, lock, language FROM script WHERE hash = $1 AND (workspace_id = $2 OR workspace_id = 'starter')")
.bind(&job.script_hash.unwrap_or(ScriptHash(0)).0)
.bind(&job.workspace_id)
.fetch_optional(db)
.await?
.ok_or_else(|| Error::InternalErr(format!("expected content and lock")))?
};
match language {
None => {
return Err(Error::ExecutionErr(
"Require language to be not null".to_string(),
))?;
}
Some(ScriptLang::Python3) => {
let requirements =
requirements_o.ok_or_else(|| Error::InternalErr(format!("lockfile missing")))?;
let _ = write_file(
job_dir,
"download.config.proto",
&NSJAIL_CONFIG_DOWNLOAD_CONTENT
.replace("{JOB_DIR}", job_dir)
.replace("{WORKER_DIR}", &worker_dir)
.replace("{CACHE_DIR}", PIP_CACHE_DIR)
.replace("{CLONE_NEWUSER}", &(!disable_nuser).to_string()),
)
.await?;
let _ = write_file(job_dir, "requirements.txt", &requirements).await?;
let child = Command::new("nsjail")
.current_dir(job_dir)
.args(vec!["--config", "download.config.proto"])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
logs.push_str("\n--- PIP DEPENDENCIES INSTALL ---\n");
*status = handle_child(job, db, logs, last_line, timeout, child).await;
if status.is_ok() {
logs.push_str("\n\n--- PTHON CODE EXECUTION ---\n");
set_logs(logs, job.id, db).await;
let _ = write_file(job_dir, "inner.py", &inner_content).await?;
let sig = crate::parser::parse_python_signature(&inner_content)?;
let transforms = sig.args.into_iter().map(|x| match x.typ {
Typ::Bytes => format!("if \"{}\" in kwargs and kwargs[\"{}\"] is not None:\n kwargs[\"{}\"] = base64.b64decode(kwargs[\"{}\"])\n", x.name, x.name, x.name, x.name),
Typ::Datetime => format!("if \"{}\" in kwargs and kwargs[\"{}\"] is not None:\n kwargs[\"{}\"] = datetime.strptime(kwargs[\"{}\"], '%Y-%m-%dT%H:%M')\n", x.name, x.name, x.name, x.name),
_ => "".to_string()
}).collect::<Vec<String>>().join("");
let tx = db.begin().await?;
let token = create_token_for_owner(
&db,
&job.workspace_id,
&job.permissioned_as,
crate::users::NewToken {
label: Some("ephemeral-script".to_string()),
expiration: Some(
chrono::Utc::now() + chrono::Duration::seconds((timeout * 2).into()),
),
},
&job.created_by,
)
.await?;
let args = if let Some(args) = &job.args {
Some(
transform_json_value(&token, &job.workspace_id, base_url, args.clone())
.await,
)
} else {
None
};
let ser_args = serde_json::to_string(&args)
.map_err(|e| Error::ExecutionErr(e.to_string()))?
.replace("\\\"", "\\\\\"");
let wrapper_content: String = format!(
r#"
import json
import base64
from datetime import datetime
inner_script = __import__("inner")
kwargs = json.loads("""{ser_args}""", strict=False)
for k, v in kwargs.items():
if v == '<function call>':
kwargs[k] = None
{transforms}
res = inner_script.main(**kwargs)
if res is None:
res = {{}}
if isinstance(res, tuple):
res = {{f"res{{i+1}}": v for i, v in enumerate(res)}}
if not isinstance(res, dict):
res = {{ "res1": res }}
res_json = json.dumps(res, separators=(',', ':'), default=str).replace('\n', '')
print()
print("result:")
print(res_json)
"#,
);
write_file(job_dir, "main.py", &wrapper_content).await?;
tx.commit().await?;
let reserved_variables = get_reserved_variables(job, token, db).await?;
let _ = write_file(
job_dir,
"run.config.proto",
&NSJAIL_CONFIG_RUN_PYTHON3_CONTENT
.replace("{JOB_DIR}", job_dir)
.replace("{CLONE_NEWUSER}", &(!disable_nuser).to_string()),
)
.await?;
let child = Command::new("nsjail")
.current_dir(job_dir)
.envs(reserved_variables)
.args(vec![
"--config",
"run.config.proto",
"--",
"/usr/local/bin/python3",
"-u",
"/tmp/main.py",
])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
*status = handle_child(job, db, logs, last_line, timeout, child).await;
}
}
Some(ScriptLang::Deno) => {
logs.push_str("\n\n--- DENO CODE EXECUTION ---\n");
set_logs(logs, job.id, db).await;
let _ = write_file(job_dir, "inner.ts", &inner_content).await?;
let sig = crate::parser::parse_deno_signature(&inner_content)?;
// let transforms = sig.args.clone().into_iter().map(|x| match x.typ {
// Typ::Bytes => format!("if \"{}\" in kwargs and kwargs[\"{}\"] is not None:\n kwargs[\"{}\"] = base64.b64decode(kwargs[\"{}\"])\n", x.name, x.name, x.name, x.name),
// Typ::Datetime => format!("if \"{}\" in kwargs and kwargs[\"{}\"] is not None:\n kwargs[\"{}\"] = datetime.strptime(kwargs[\"{}\"], '%Y-%m-%dT%H:%M')\n", x.name, x.name, x.name, x.name),
// _ => "".to_string()
// }).collect::<Vec<String>>().join("");
let tx = db.begin().await?;
let token = create_token_for_owner(
&db,
&job.workspace_id,
&job.permissioned_as,
crate::users::NewToken {
label: Some("ephemeral-script".to_string()),
expiration: Some(
chrono::Utc::now() + chrono::Duration::seconds((timeout * 2).into()),
),
},
&job.created_by,
)
.await?;
let args = if let Some(args) = &job.args {
Some(transform_json_value(&token, &job.workspace_id, base_url, args.clone()).await)
} else {
None
};
let ser_args = serde_json::to_string(&args)
.map_err(|e| Error::ExecutionErr(e.to_string()))?
.replace("\\\"", "\\\\\"");
let spread = sig.args.into_iter().map(|x| x.name).join(",");
let wrapper_content: String = format!(
r#"
import {{ main }} from "./inner.ts";
const {{{spread}}} = JSON.parse(`{ser_args}`);
async function run() {{
let res: any = await main({spread});
if (res == undefined) {{
res = {{}}
}}
if (typeof res !== 'object') {{
res = {{ res1: res }}
}}
const res_json = JSON.stringify(res);
console.log();
console.log("result:");
console.log(res_json);
Deno.exit(0);
}}
run();
"#,
);
write_file(job_dir, "main.ts", &wrapper_content).await?;
tx.commit().await?;
let reserved_variables = get_reserved_variables(job, token, db).await?;
let _ = write_file(
job_dir,
"run.config.proto",
&NSJAIL_CONFIG_RUN_DENO_CONTENT
.replace("{JOB_DIR}", job_dir)
.replace("{CACHE_DIR}", DENO_CACHE_DIR)
.replace("{CLONE_NEWUSER}", &(!disable_nuser).to_string()),
)
.await?;
let child = Command::new("nsjail")
.current_dir(job_dir)
.envs(reserved_variables)
.args(vec![
"--config",
"run.config.proto",
"--",
"/usr/bin/deno",
"run",
"--unstable",
"--v8-flags=--max-heap-size=2048",
"-A",
"/tmp/main.ts",
])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
*status = handle_child(job, db, logs, last_line, timeout, child).await;
}
}
Ok(())
}
async fn handle_dependency_job(
job: &QueuedJob,
logs: &mut String,
job_dir: &String,
status: &mut Result<ExitStatus, Error>,
db: &sqlx::Pool<sqlx::Postgres>,
last_line: &mut String,
timeout: i32,
) -> Result<(), Error> {
let requirements = job
.raw_code
.as_ref()
.ok_or_else(|| Error::ExecutionErr("missing requirements".to_string()))?;
logs.push_str(&format!("content of requirements:\n{}\n", &requirements));
let file = "requirements.in";
write_file(job_dir, file, &requirements).await?;
let child = Command::new("pip-compile")
.current_dir(job_dir)
.args(vec!["-q", "--no-header", file])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
*status = handle_child(job, db, logs, last_line, timeout, child).await;
Ok(if status.is_ok() && status.as_ref().unwrap().success() {
let path_lock = format!("{}/requirements.txt", job_dir);
let mut file = File::open(path_lock).await?;
let mut content = "".to_string();
file.read_to_string(&mut content).await?;
content = content
.lines()
.filter(|x| !x.trim_start().starts_with('#'))
.map(|x| x.to_string())
.collect::<Vec<String>>()
.join("\n");
let as_json = json!(content);
*last_line =
format!(r#"{{ "success": "Successful lock file generation", "lock": {as_json} }}"#);
sqlx::query!(
"UPDATE script SET lock = $1 WHERE hash = $2 AND workspace_id = $3",
&content,
&job.script_hash.unwrap_or(ScriptHash(0)).0,
&job.workspace_id
)
.execute(db)
.await?;
} else {
sqlx::query!(
"UPDATE script SET lock_error_logs = $1 WHERE hash = $2 AND workspace_id = $3",
&logs.clone(),
&job.script_hash.unwrap_or(ScriptHash(0)).0,
&job.workspace_id
)
.execute(db)
.await?;
})
}
async fn get_reserved_variables(
job: &QueuedJob,
token: String,
db: &sqlx::Pool<sqlx::Postgres>,
) -> Result<HashMap<String, String>, Error> {
let flow_path = if let Some(uuid) = job.parent_job {
sqlx::query_scalar!("SELECT script_path FROM queue WHERE id = $1", uuid)
.fetch_optional(db)
.await?
.flatten()
} else {
None
};
let variables = variables::get_reserved_variables(
&job.workspace_id,
&token,
&get_email_from_username(&job.created_by, db)
.await?
.unwrap_or_else(|| "nosuitable@email.xyz".to_string()),
&job.created_by,
&job.id.to_string(),
&job.permissioned_as,
job.script_path.clone(),
flow_path,
);
Ok(variables
.into_iter()
.map(|rv| (rv.name, rv.value))
.collect())
}
async fn handle_child(
job: &QueuedJob,
db: &DB,

View File

@@ -53,7 +53,8 @@ struct Workspace {
name: String,
owner: String,
domain: Option<String>,
deleted: bool
deleted: bool,
premium: bool
}
#[derive(FromRow, Serialize, Debug)]

Binary file not shown.

View File

@@ -1,6 +1,6 @@
{
"workspace_id": "starter",
"name": "SMTP",
"name": "email_smtp",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
@@ -28,5 +28,5 @@
}
}
},
"description": "SMTP connection info"
}
"description": "SMTP connection infos"
}

View File

@@ -34,5 +34,5 @@
}
}
},
"description": "MongoDB connection info"
}
"description": "Mongodb connection infos"
}

View File

@@ -32,5 +32,5 @@
}
}
},
"description": "MySQL connection info"
}
"description": "MySql connection info"
}

View File

@@ -1,6 +1,6 @@
{
"workspace_id": "starter",
"name": "postgres",
"name": "postgresql",
"schema": {
"type": "object",
"$schema": "https://json-schema.org/draft/2020-12/schema",
@@ -44,5 +44,5 @@
}
}
},
"description": "A postgres database connection resource"
}
"description": "Postgres connection info"
}

View File

@@ -12,5 +12,5 @@
}
}
},
"description": "A slack token to interact with a specific workspace. Can be obtained from the OAuth integration in the workspace settings."
}
"description": "Slack token"
}

View File

@@ -10,6 +10,6 @@
"password": "demodb"
},
"description": "demodb",
"resource_type": "postgres",
"resource_type": "postgresql",
"extra_perms": {}
}
}

View File

@@ -12,7 +12,7 @@
"description": "",
"type": "object",
"default": null,
"format": "resource-postgres"
"format": "resource-postgresql"
},
"sql_query": {
"description": "",
@@ -40,4 +40,4 @@
"wmill==1.5.0",
"wmill-pg==1.5.0"
]
}
}

View File

@@ -15,7 +15,7 @@
"description": "",
"type": "object",
"default": null,
"format": "resource-SMTP"
"format": "resource-smtp"
},
"to": {
"type": "string",
@@ -54,4 +54,4 @@
"windmill-api==1.5.0",
"wmill==1.5.0"
]
}
}

1
deno-client/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
windmill-api

5
deno-client/.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,5 @@
{
"deno.enable": true,
"deno.lint": true,
"deno.unstable": true
}

6
deno-client/generate.sh Executable file
View File

@@ -0,0 +1,6 @@
#!/bin/bash
set -e
/usr/local/bin/docker-entrypoint.sh generate -i ../backend/openapi.yaml -g typescript --additional-properties platform=deno -o windmill-api
sed -i 's/this\.type = "Job";//' windmill-api/models/Job.ts
sed -i '439 i \ if (mediaType === "text/plain") { return rawData }' windmill-api/models/ObjectSerializer.ts

125
deno-client/mod.ts Normal file
View File

@@ -0,0 +1,125 @@
import { ResourceApi, VariableApi, ServerConfiguration } from './windmill-api/index.ts'
import { createConfiguration, type Configuration as Configuration } from './windmill-api/configuration.ts'
export {
AdminApi, AuditApi, FlowApi, GranularAclApi, GroupApi,
JobApi, ResourceApi, VariableApi, ScriptApi, ScheduleApi, SettingsApi,
UserApi, WorkspaceApi
} from './windmill-api/index.ts'
export type Email = string
export type Base64 = string
export type Resource<S extends string> = {}
/**
* Create a client configuration from env variables
* @returns client configuration
*/
export function createConf(): Configuration & { workspace_id: string } {
const token = Deno.env.get("WM_TOKEN") ?? 'no_token'
const base_url = Deno.env.get("BASE_INTERNAL_URL") ?? 'http://localhost:8000'
return {
...createConfiguration({
baseServer: new ServerConfiguration(`${base_url}/api`, {}),
authMethods: { bearerAuth: { tokenProvider: { getToken() { return token } } } },
}), workspace_id: Deno.env.get("WM_WORKSPACE") ?? 'no_workspace'
}
}
/**
* Get a resource value by path
* @param path path of the resource
* @returns resource value
*/
export async function getResource(path: string, initializeToTypeIfNotExist?: string): Promise<any> {
const conf = createConf()
try {
const resource = await new ResourceApi(conf).getResource(conf.workspace_id, path)
return await transformLeaves(resource.value)
} catch (e) {
if (initializeToTypeIfNotExist && e.code === 404) {
await new ResourceApi(conf).createResource(conf.workspace_id, { path, value: {}, resourceType: initializeToTypeIfNotExist })
return undefined
} else {
throw e
}
}
}
export function getInternalStatePath(suffix?: string): string {
const env_flow_path = Deno.env.get("WM_FLOW_PATH")
const env_job_path = Deno.env.get("WM_JOB_PATH")
const permissioned_as = Deno.env.get("WM_PERMISSIONED_AS")
const flow_path = env_flow_path != undefined && env_flow_path != "" ? env_flow_path : 'NO_FLOW_PATH'
const script_path = suffix ?? (env_job_path != undefined && env_job_path != "" ? env_job_path : 'NO_JOB_PATH')
return `${permissioned_as}/${flow_path}/${script_path}`
}
/**
* Set a resource value by path
* @param path path of the resource to set
* @param value new value of the resource to set
* @param initializeToTypeIfNotExist if the resource does not exist, initialize it with this type
*/
export async function setResource(path: string, value: any, initializeToTypeIfNotExist?: string): Promise<void> {
const conf = createConf()
try {
await new ResourceApi(conf).updateResource(conf.workspace_id, path, { value })
} catch (e) {
if (initializeToTypeIfNotExist && e.code === 404) {
await new ResourceApi(conf).createResource(conf.workspace_id, { path, value, resourceType: initializeToTypeIfNotExist })
} else {
throw e
}
}
}
/**
* Set the internal state
* @param state state to set
* @param suffix suffix of the path of the internal state (useful to share internal state between jobs)
*/
export async function setInternalState(state: any, suffix?: string): Promise<void> {
await setResource(getInternalStatePath(suffix), state, 'state')
}
/**
* Get the internal state
* @param suffix suffix of the path of the internal state (useful to share internal state between jobs)
*/
export async function getInternalState(suffix?: string): Promise<any> {
return await getResource(getInternalStatePath(suffix), 'state')
}
/**
* Get a variable by path
* @param path path of the variable
* @returns variable value
*/
export async function getVariable(path: string): Promise<string | undefined> {
const conf = createConf()
const variable = await new VariableApi(conf).getVariable(conf.workspace_id, path)
return variable.value
}
async function transformLeaves(d: { [key: string]: any }): Promise<{ [key: string]: any }> {
for (const k in d) {
d[k] = await _transformLeaf(d[k])
}
return d
}
const VAR_RESOURCE_PREFIX = "$var:"
async function _transformLeaf(v: any): Promise<any> {
if (typeof v === 'object') {
return transformLeaves(v)
}
else if (typeof v === 'string' && v.startsWith(VAR_RESOURCE_PREFIX)) {
const varName = v.substring(VAR_RESOURCE_PREFIX.length)
return await getVariable(varName)
} else {
return v
}
}

View File

@@ -0,0 +1,7 @@
{
"$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",
"spaces": 2,
"generator-cli": {
"version": "6.0.0-beta"
}
}

View File

@@ -3,10 +3,11 @@ version: '3.7'
services:
db:
image: postgres:13
image: postgres:14
restart: always
volumes:
- db_data:/var/lib/postgresql/data
- ./init-db.sql:/docker-entrypoint-initdb.d/create_tables.sql
ports:
- 5432:5432
environment:
@@ -18,30 +19,26 @@ services:
timeout: 5s
retries: 5
windmill:
image: windmill:main
image: ghcr.io/windmill-labs/windmill:main
privileged: true
restart: unless-stopped
ports:
- 8000:8000
- 80:8000
environment:
- DATABASE_URL=postgres://postgres:${DB_PASSWORD}@db/windmill?sslmode=disable
- VARIABLES_KEY=changeme
- APP_USER_PASSWORD=changeme
- BASE_URL=http://localhost
- BASE_INTERNAL_URL=http://localhost:8000
- RUST_LOG=info
- NUM_WORKERS=3
- RUST_BACKTRACE=1
- GITHUB_OAUTH_CLIENT_ID=${GITHUB_OAUTH_CLIENT_ID}
- GITHUB_OAUTH_CLIENT_SECRET=${GITHUB_OAUTH_CLIENT_SECRET}
- DISABLE_NUSER=false
depends_on:
db:
condition: service_healthy
caddy:
image: caddy
restart: unless-stopped
environment:
- SITE_URL=${SITE_URL}
ports:
- 80:80
- 443:443
volumes:
- $PWD/Caddyfile:/etc/caddy/Caddyfile
- caddy_data:/data
volumes:
caddy_data:
external: true
db_data: null

View File

@@ -20,4 +20,4 @@ module.exports = {
rules: {
'no-console': ['log', { allow: ['warn', 'error'] }]
}
};
}

4
frontend/.gitignore vendored
View File

@@ -3,6 +3,6 @@ node_modules
/build
/.svelte-kit
/package
/src/gen
/src/lib/gen
CaddyfileRemoteRuben
cypress/videos

1
frontend/.nvmrc Normal file
View File

@@ -0,0 +1 @@
v17.9.0

View File

@@ -2,5 +2,6 @@
"useTabs": true,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100
"printWidth": 100,
"semi": false
}

View File

@@ -5,4 +5,8 @@
bind {$ADDRESS}
reverse_proxy /api/* http://localhost:8000
reverse_proxy /* http://localhost:3000
reverse_proxy /ws/* http://localhost:3001 {
lb_policy header "Authorization"
}
}

View File

@@ -1,16 +0,0 @@
http://localhost {
bind {$ADDRESS}
reverse_proxy /api/* https://demo.windmill.dev {
header_up Host {http.reverse_proxy.upstream.hostport}
}
reverse_proxy /* http://localhost:3000
}
https://localhost {
bind {$ADDRESS}
reverse_proxy /ws/* https://demo.windmill.dev {
header_up Host {http.reverse_proxy.upstream.hostport}
}
}

View File

@@ -1,6 +1,6 @@
http://localhost {
bind {$ADDRESS}
reverse_proxy /api/* https://alpha.windmill.dev {
reverse_proxy /api/* https://app.windmill.dev {
header_up Host {http.reverse_proxy.upstream.hostport}
}
reverse_proxy /* http://localhost:3000
@@ -9,7 +9,7 @@ http://localhost {
https://localhost {
bind {$ADDRESS}
reverse_proxy /ws/* https://alpha.windmill.dev {
reverse_proxy /ws/* https://app.windmill.dev {
header_up Host {http.reverse_proxy.upstream.hostport}
}
}

6
frontend/cypress.json Normal file
View File

@@ -0,0 +1,6 @@
{
"pluginsFile": false,
"env": {
"baseUrl": "http://localhost:8000"
}
}

View File

@@ -0,0 +1,18 @@
// TODO: Should correctly handle exceptions
Cypress.on('uncaught:exception', (err, runnable) => {
// returning false here prevents Cypress from
// failing the test
return false
})
describe('Authentication', () => {
it('can login using email and password', () => {
cy.login('admin@windmill.dev', 'changeme')
cy.contains('Select a workspace')
})
it('should redirect to login page if user is not logged in', () => {
cy.visit(`${Cypress.env('baseUrl')}/user/workspaces`)
cy.url().should('include', '/user/login')
})
})

View File

@@ -0,0 +1,7 @@
Cypress.Commands.add('login', (email: string, password: string) => {
cy.visit(`${Cypress.env('baseUrl')}/user/login`)
cy.get('#showPassword').click()
cy.get('#email').type('admin@windmill.dev')
cy.get('#password').type('changeme')
cy.get('.flex > .default-button').click()
})

View File

@@ -0,0 +1,8 @@
import './commands'
declare global {
namespace Cypress {
interface Chainable {
login: (email: string, password: string) => Chainable<Element>
}
}
}

View File

@@ -0,0 +1,8 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["es5", "dom"],
"types": ["cypress"]
},
"include": ["**/*.ts"]
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "windmill",
"version": "1.5.0",
"version": "1.14.5",
"scripts": {
"dev": "svelte-kit dev",
"build": "svelte-kit build",
@@ -9,49 +9,53 @@
"check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --ignore-path .gitignore --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .",
"format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. .",
"generate-backend-client": "openapi --input ../backend/openapi.yaml --output ./src/gen --useOptions"
"package": "svelte-kit package && cd package && rm README.md && rm README_DEV.md && sed -i -e 's/windmill/windmill-components/g' package.json",
"generate-backend-client": "openapi --input ../backend/openapi.yaml --output ./src/lib/gen --useOptions",
"cypress:open": "cypress open",
"cypress:run": "cypress run"
},
"devDependencies": {
"@sveltejs/adapter-node": "^1.0.0-next.55",
"@sveltejs/adapter-static": "^1.0.0-next.21",
"@sveltejs/adapter-node": "^1.0.0-next.78",
"@sveltejs/adapter-static": "^1.0.0-next.34",
"@sveltejs/kit": "next",
"@tailwindcss/forms": "^0.4.0",
"@tailwindcss/forms": "^0.5.1",
"@tailwindcss/typography": "^0.5.0",
"@typescript-eslint/eslint-plugin": "^4.31.1",
"@typescript-eslint/parser": "^4.31.1",
"@typescript-eslint/eslint-plugin": "^5.27.0",
"@typescript-eslint/parser": "^5.27.0",
"@zerodevx/svelte-toast": "^0.7.2",
"autoprefixer": "^10.4.1",
"cssnano": "^5.0.8",
"eslint": "^7.32.0",
"cssnano": "^5.1.10",
"cypress": "^9.7.0",
"eslint": "^8.16.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-svelte3": "^3.2.1",
"openapi-typescript-codegen": "^0.11.8",
"eslint-plugin-svelte3": "^4.0.0",
"openapi-typescript-codegen": "^0.22.0",
"postcss": "^8.4.5",
"postcss-load-config": "^3.1.0",
"postcss-load-config": "^4.0.1",
"prettier": "^2.4.1",
"prettier-plugin-svelte": "^2.4.0",
"simple-svelte-autocomplete": "^2.2.4",
"stylelint-config-recommended": "^6.0.0",
"stylelint-config-recommended": "^7.0.0",
"svelte": "^3.42.6",
"svelte-awesome": "^2.4.2",
"svelte-check": "^2.2.6",
"svelte-highlight": "^5.1.3",
"svelte-highlight": "^6.0.1",
"svelte-preprocess": "^4.9.8",
"svelte2tsx": "^0.5.10",
"tailwindcss": "^3.0.11",
"tslib": "^2.3.1",
"typescript": "^4.4.3"
"typescript": "^4.7.4"
},
"type": "module",
"dependencies": {
"@codingame/monaco-jsonrpc": "^0.3.1",
"@codingame/monaco-languageclient": "^0.17.0",
"@fortawesome/free-brands-svg-icons": "^5.15.4",
"@fortawesome/free-solid-svg-icons": "^5.15.4",
"@codingame/monaco-jsonrpc": "^0.4.0",
"@fortawesome/free-brands-svg-icons": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1",
"@types/vscode": "^1.63.0",
"@zerodevx/svelte-toast": "^0.6.2",
"fuse.js": "^6.4.6",
"highlight.js": "^11.5.1",
"monaco-editor": "^0.30.0",
"svelte-awesome": "^2.4.2",
"monaco-editor": "^0.33.0",
"monaco-languageclient": "^1.0.1",
"svelte-awesome": "^3.0.0",
"svelte-markdown": "^0.2.1",
"svelte-split-pane": "^0.1.2"
}

View File

@@ -1,9 +1,9 @@
const tailwindcss = require('tailwindcss');
const autoprefixer = require('autoprefixer');
const cssnano = require('cssnano');
const tailwindcss = require('tailwindcss')
const autoprefixer = require('autoprefixer')
const cssnano = require('cssnano')
const mode = process.env.NODE_ENV;
const dev = mode === 'development';
const mode = process.env.NODE_ENV
const dev = mode === 'development'
const config = {
plugins: [
@@ -16,6 +16,6 @@ const config = {
preset: 'default'
})
]
};
}
module.exports = config;
module.exports = config

2
frontend/src/.d.ts vendored
View File

@@ -1,5 +1,5 @@
declare namespace svelte.JSX {
interface DOMAttributes<T> {
onclick_outside?: CompositionEventHandler<T>;
onclick_outside?: CompositionEventHandler<T>
}
}

View File

@@ -6,11 +6,11 @@
<link rel="icon" href="/logo.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>windmill.dev</title>
%svelte.head%
%sveltekit.head%
</head>
<body class="outline-none focus:outline-none">
%svelte.body%
%sveltekit.body%
</body>
</html>

View File

@@ -1,24 +0,0 @@
export function pathToMeta(path) {
const splitted = path.split('/');
let ownerKind;
if (splitted[0] == 'g') {
ownerKind = 'group';
}
else if (splitted[0] == 'u') {
ownerKind = 'user';
}
else {
console.error('Not recognized owner:' + splitted[0]);
return {
ownerKind: 'user',
owner: '',
name: ''
};
}
return {
ownerKind,
owner: splitted[1],
name: splitted.slice(2).join('/')
};
}
//# sourceMappingURL=common.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"common.js","sourceRoot":"","sources":["common.ts"],"names":[],"mappings":"AA0BA,MAAM,UAAU,UAAU,CAAC,IAAY;IACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAChC,IAAI,SAAoB,CAAA;IACxB,IAAI,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE;QACvB,SAAS,GAAG,OAAO,CAAA;KACnB;SAAM,IAAI,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE;QAC9B,SAAS,GAAG,MAAM,CAAA;KAClB;SAAM;QACN,OAAO,CAAC,KAAK,CAAC,uBAAuB,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;QACpD,OAAO;YACN,SAAS,EAAE,MAAM;YACjB,KAAK,EAAE,EAAE;YACT,IAAI,EAAE,EAAE;SACR,CAAA;KACD;IACD,OAAO;QACN,SAAS;QACT,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC;QAClB,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;KACjC,CAAA;AACF,CAAC"}

View File

@@ -1,8 +0,0 @@
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
const response = await resolve(event, {
ssr: false
});
return response;
}
//# sourceMappingURL=hooks.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["hooks.ts"],"names":[],"mappings":"AAAA,6CAA6C;AAC7C,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE;IAC3C,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,KAAK,EAAE;QAClC,GAAG,EAAE,KAAK;KACb,CAAC,CAAA;IAEF,OAAO,QAAQ,CAAA;AACnB,CAAC"}

View File

@@ -1,8 +1,8 @@
/** @type {import('@sveltejs/kit').Handle} */
export async function handle({ event, resolve }) {
const response = await resolve(event, {
ssr: false
})
const response = await resolve(event, {
ssr: false
})
return response
return response
}

View File

@@ -1,66 +0,0 @@
import { ScriptService } from "./gen";
import { sendUserToast } from "./utils";
export async function inferArgs(code, schema) {
try {
const inferedSchema = await ScriptService.toJsonschema({
requestBody: code
});
schema.required = [];
const oldProperties = Object.assign({}, schema.properties);
schema.properties = {};
for (const arg of inferedSchema.args) {
if (!(arg.name in oldProperties)) {
schema.properties[arg.name] = { description: '', type: '' };
}
else {
schema.properties[arg.name] = oldProperties[arg.name];
}
pythonToJsonSchemaType(arg.typ, schema.properties[arg.name]);
schema.properties[arg.name].default = arg.default;
if (!arg.has_default) {
schema.required.push(arg.name);
}
}
}
catch (err) {
console.error(err);
sendUserToast(`Could not infer schema: ${err.body ?? err}`, true);
}
}
function array_move(arr, fromIndex, toIndex) {
var element = arr[fromIndex];
arr.splice(fromIndex, 1);
arr.splice(toIndex, 0, element);
}
function pythonToJsonSchemaType(t, s) {
if (t === 'int') {
s.type = 'integer';
}
else if (t === 'float') {
s.type = 'number';
}
else if (t === 'bool') {
s.type = 'boolean';
}
else if (t === 'str') {
s.type = 'string';
}
else if (t === 'dict') {
s.type = 'object';
}
else if (t === 'list') {
s.type = 'array';
}
else if (t === 'bytes') {
s.type = 'string';
s.contentEncoding = 'base64';
}
else if (t === 'datetime') {
s.type = 'string';
s.format = 'date-time';
}
else {
s.type = undefined;
}
}
//# sourceMappingURL=infer.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"infer.js","sourceRoot":"","sources":["infer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAEvC,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAY,EAAE,MAAc;IACxD,IAAI;QACA,MAAM,aAAa,GAAG,MAAM,aAAa,CAAC,YAAY,CAAC;YACnD,WAAW,EAAE,IAAI;SACpB,CAAC,CAAA;QACF,MAAM,CAAC,QAAQ,GAAG,EAAE,CAAA;QACpB,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,UAAU,CAAC,CAAA;QAC1D,MAAM,CAAC,UAAU,GAAG,EAAE,CAAA;QAEtB,KAAK,MAAM,GAAG,IAAI,aAAa,CAAC,IAAI,EAAE;YAClC,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,IAAI,aAAa,CAAC,EAAE;gBAC9B,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAA;aAC9D;iBAAM;gBACH,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;aACxD;YACD,sBAAsB,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAA;YAC5D,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAA;YAEjD,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE;gBAClB,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;aACjC;SACJ;KACJ;IAAC,OAAO,GAAG,EAAE;QACV,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAClB,aAAa,CAAC,2BAA2B,GAAG,CAAC,IAAI,IAAI,GAAG,EAAE,EAAE,IAAI,CAAC,CAAA;KACpE;AACL,CAAC;AAED,SAAS,UAAU,CAAI,GAAQ,EAAE,SAAiB,EAAE,OAAe;IAC/D,IAAI,OAAO,GAAG,GAAG,CAAC,SAAS,CAAC,CAAA;IAC5B,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAA;IACxB,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,EAAE,OAAO,CAAC,CAAA;AACnC,CAAC;AAED,SAAS,sBAAsB,CAAC,CAAS,EAAE,CAAiB;IACxD,IAAI,CAAC,KAAK,KAAK,EAAE;QACb,CAAC,CAAC,IAAI,GAAG,SAAS,CAAA;KACrB;SAAM,IAAI,CAAC,KAAK,OAAO,EAAE;QACtB,CAAC,CAAC,IAAI,GAAG,QAAQ,CAAA;KACpB;SAAM,IAAI,CAAC,KAAK,MAAM,EAAE;QACrB,CAAC,CAAC,IAAI,GAAG,SAAS,CAAA;KACrB;SAAM,IAAI,CAAC,KAAK,KAAK,EAAE;QACpB,CAAC,CAAC,IAAI,GAAG,QAAQ,CAAA;KACpB;SAAM,IAAI,CAAC,KAAK,MAAM,EAAE;QACrB,CAAC,CAAC,IAAI,GAAG,QAAQ,CAAA;KACpB;SAAM,IAAI,CAAC,KAAK,MAAM,EAAE;QACrB,CAAC,CAAC,IAAI,GAAG,OAAO,CAAA;KACnB;SAAM,IAAI,CAAC,KAAK,OAAO,EAAE;QACtB,CAAC,CAAC,IAAI,GAAG,QAAQ,CAAA;QACjB,CAAC,CAAC,eAAe,GAAG,QAAQ,CAAA;KAC/B;SAAM,IAAI,CAAC,KAAK,UAAU,EAAE;QACzB,CAAC,CAAC,IAAI,GAAG,QAAQ,CAAA;QACjB,CAAC,CAAC,MAAM,GAAG,WAAW,CAAA;KACzB;SAAM;QACH,CAAC,CAAC,IAAI,GAAG,SAAS,CAAA;KACrB;AACL,CAAC"}

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