diff --git a/README.md b/README.md index 31e8c2b..ba14ba8 100644 --- a/README.md +++ b/README.md @@ -81,13 +81,13 @@ Requirements: **Latest (Desktop):** -- `Mac`: arm64: [fluentci-studio_v0.1.9_arm64.dmg](https://github.com/fluentci-io/fluentci-studio/releases/download/v0.1.9/fluentci-studio_v0.1.9_arm64.dmg) intel: [fluentci-studio_v0.1.9_x64.dmg](https://github.com/fluentci-io/fluentci-studio/releases/download/v0.1.9/fluentci-studio_v0.1.9_x64.dmg) -- `Linux`: [fluentci-studio_v0.1.9.AppImage](https://github.com/fluentci-io/fluentci-studio/releases/download/v0.1.9/fluentci-studio_v0.1.9.AppImage) +- `Mac`: arm64: [fluentci-studio_v0.2.0_arm64.dmg](https://github.com/fluentci-io/fluentci-studio/releases/download/v0.2.0/fluentci-studio_v0.2.0_arm64.dmg) intel: [fluentci-studio_v0.2.0_x64.dmg](https://github.com/fluentci-io/fluentci-studio/releases/download/v0.2.0/fluentci-studio_v0.2.0_x64.dmg) +- `Linux`: [fluentci-studio_v0.2.0.AppImage](https://github.com/fluentci-io/fluentci-studio/releases/download/v0.2.0/fluentci-studio_v0.2.0.AppImage) **Latest (CLI):** -- `Mac`: arm64: [fluentci_v0.15.9_aarch64-apple-darwin.tar.gz](https://github.com/fluentci-io/fluentci/releases/download/v0.15.9/fluentci_v0.15.9_aarch64-apple-darwin.tar.gz) intel: [fluentci_v0.15.9_x86_64-apple-darwin.tar.gz](https://github.com/fluentci-io/fluentci/releases/download/v0.15.9/fluentci_v0.15.9_x86_64-apple-darwin.tar.gz) -- `Linux`: intel: [fluentci_v0.15.9_x86_64-unknown-linux-gnu.tar.gz](https://github.com/fluentci-io/fluentci/releases/download/v0.15.9/fluentci_v0.15.9_x86_64-unknown-linux-gnu.tar.gz) arm64: [fluentci_v0.15.9_aarch64-unknown-linux-gnu.tar.gz](https://github.com/fluentci-io/fluentci/releases/download/v0.15.9/fluentci_v0.15.9_aarch64-unknown-linux-gnu.tar.gz) +- `Mac`: arm64: [fluentci_v0.16.0_aarch64-apple-darwin.tar.gz](https://github.com/fluentci-io/fluentci/releases/download/v0.16.0/fluentci_v0.16.0_aarch64-apple-darwin.tar.gz) intel: [fluentci_v0.16.0_x86_64-apple-darwin.tar.gz](https://github.com/fluentci-io/fluentci/releases/download/v0.16.0/fluentci_v0.16.0_x86_64-apple-darwin.tar.gz) +- `Linux`: intel: [fluentci_v0.16.0_x86_64-unknown-linux-gnu.tar.gz](https://github.com/fluentci-io/fluentci/releases/download/v0.16.0/fluentci_v0.16.0_x86_64-unknown-linux-gnu.tar.gz) arm64: [fluentci_v0.16.0_aarch64-unknown-linux-gnu.tar.gz](https://github.com/fluentci-io/fluentci/releases/download/v0.16.0/fluentci_v0.16.0_aarch64-unknown-linux-gnu.tar.gz) ## ✨ Quick Start @@ -110,7 +110,7 @@ fluentci studio fluentci --help Usage: fluentci [pipeline] [jobs...] -Version: 0.15.9 +Version: 0.16.0 Description: diff --git a/deno.json b/deno.json index 51c035c..2d68016 100644 --- a/deno.json +++ b/deno.json @@ -23,7 +23,8 @@ }, "test": { "exclude": [ - ".fluentci/" + ".fluentci/", + "demo*" ] } } \ No newline at end of file diff --git a/deno.lock b/deno.lock index d130ca0..3b4d866 100644 --- a/deno.lock +++ b/deno.lock @@ -2,44 +2,98 @@ "version": "3", "packages": { "specifiers": { + "jsr:@cliffy/ansi@1.0.0-rc.5": "jsr:@cliffy/ansi@1.0.0-rc.5", + "jsr:@cliffy/internal@1.0.0-rc.5": "jsr:@cliffy/internal@1.0.0-rc.5", + "jsr:@cliffy/keycode@1.0.0-rc.5": "jsr:@cliffy/keycode@1.0.0-rc.5", + "jsr:@cliffy/prompt@1.0.0-rc.5": "jsr:@cliffy/prompt@1.0.0-rc.5", + "jsr:@cliffy/table@1.0.0-rc.5": "jsr:@cliffy/table@1.0.0-rc.5", + "jsr:@denosaurs/event": "jsr:@denosaurs/event@2.0.2", "jsr:@jotsr/delayed@2.1.1": "jsr:@jotsr/delayed@2.1.1", + "jsr:@std/assert": "jsr:@std/assert@1.0.3", + "jsr:@std/assert@1.0.0-rc.2": "jsr:@std/assert@1.0.0-rc.2", "jsr:@std/assert@^0.217.0": "jsr:@std/assert@0.217.0", "jsr:@std/assert@^0.224.0": "jsr:@std/assert@0.224.0", "jsr:@std/async@^0.224.0": "jsr:@std/async@0.224.2", "jsr:@std/bytes@^0.224.0": "jsr:@std/bytes@0.224.0", + "jsr:@std/bytes@^1.0.2": "jsr:@std/bytes@1.0.2", + "jsr:@std/cli@1.0.0-rc.2": "jsr:@std/cli@1.0.0-rc.2", + "jsr:@std/collections@^1.0.5": "jsr:@std/collections@1.0.5", "jsr:@std/dotenv@0.224.0": "jsr:@std/dotenv@0.224.0", + "jsr:@std/encoding@1.0.0-rc.2": "jsr:@std/encoding@1.0.0-rc.2", "jsr:@std/fmt@0.224.0": "jsr:@std/fmt@0.224.0", "jsr:@std/fmt@^0.217.0": "jsr:@std/fmt@0.217.0", + "jsr:@std/fmt@~0.225.4": "jsr:@std/fmt@0.225.6", "jsr:@std/fs@0.224.0": "jsr:@std/fs@0.224.0", "jsr:@std/http@0.224.0": "jsr:@std/http@0.224.0", + "jsr:@std/internal@^1.0.2": "jsr:@std/internal@1.0.2", "jsr:@std/io@0.224.0": "jsr:@std/io@0.224.0", - "jsr:@std/io@^0.224.0": "jsr:@std/io@0.224.0", + "jsr:@std/io@^0.224.0": "jsr:@std/io@0.224.6", + "jsr:@std/io@~0.224.2": "jsr:@std/io@0.224.6", "jsr:@std/path@0.224.0": "jsr:@std/path@0.224.0", + "jsr:@std/path@1.0.0-rc.2": "jsr:@std/path@1.0.0-rc.2", "jsr:@std/path@^0.224.0": "jsr:@std/path@0.224.0", "jsr:@std/semver@0.224.0": "jsr:@std/semver@0.224.0", "jsr:@std/streams@0.224.0": "jsr:@std/streams@0.224.0", "jsr:@std/testing@0.217.0": "jsr:@std/testing@0.217.0", + "jsr:@std/text@1.0.0-rc.1": "jsr:@std/text@1.0.0-rc.1", + "jsr:@std/toml": "jsr:@std/toml@1.0.1", "jsr:@tsirysndr/fluent-az-pipelines@0.3.1": "jsr:@tsirysndr/fluent-az-pipelines@0.3.1", "jsr:@tsirysndr/fluent-circleci@0.3.1": "jsr:@tsirysndr/fluent-circleci@0.3.1", "jsr:@tsirysndr/fluent-codepipeline@0.3": "jsr:@tsirysndr/fluent-codepipeline@0.3.0", "jsr:@tsirysndr/fluent-gh-actions@0.3": "jsr:@tsirysndr/fluent-gh-actions@0.3.0", "jsr:@tsirysndr/fluent-gitlab-ci@0.5": "jsr:@tsirysndr/fluent-gitlab-ci@0.5.0", "npm:@paralleldrive/cuid2": "npm:@paralleldrive/cuid2@2.2.2", + "npm:@types/node": "npm:@types/node@18.16.19", "npm:buffer": "npm:buffer@6.0.3", - "npm:dayjs": "npm:dayjs@1.11.12", + "npm:dayjs": "npm:dayjs@1.11.13", "npm:docker-names-ts": "npm:docker-names-ts@1.2.4", "npm:graphql-request@6.1.0": "npm:graphql-request@6.1.0_graphql@16.8.1", "npm:graphql@16.8.1": "npm:graphql@16.8.1", "npm:lodash@4.17.21": "npm:lodash@4.17.21", "npm:node-color-log@11.0.2": "npm:node-color-log@11.0.2", "npm:procfile": "npm:procfile@0.1.1", - "npm:toml@3.0.0": "npm:toml@3.0.0", - "npm:tomlify-j0.4@3.0.0": "npm:tomlify-j0.4@3.0.0", "npm:typescript": "npm:typescript@5.5.4", "npm:yaml@2.3.1": "npm:yaml@2.3.1", "npm:zod@3.22.1": "npm:zod@3.22.1" }, "jsr": { + "@cliffy/ansi@1.0.0-rc.5": { + "integrity": "85a4dba4da5d8278dcdfeea98672cd15706c244833f82edc60c61f410d9fc1a9", + "dependencies": [ + "jsr:@cliffy/internal@1.0.0-rc.5", + "jsr:@std/encoding@1.0.0-rc.2", + "jsr:@std/io@~0.224.2" + ] + }, + "@cliffy/internal@1.0.0-rc.5": { + "integrity": "1e8dca4fcfba1815bf1a899bb880e09f8b45284c352465ef8fb015887c1fc126" + }, + "@cliffy/keycode@1.0.0-rc.5": { + "integrity": "2bcb3cb13873f0b758664394e003fc0cfa751af37a076ca9ec6e574df77aa3a8" + }, + "@cliffy/prompt@1.0.0-rc.5": { + "integrity": "3573a4c5c460fc84dcc554e548acfc2616157b60a61a9781833967c5a76da9f0", + "dependencies": [ + "jsr:@cliffy/ansi@1.0.0-rc.5", + "jsr:@cliffy/internal@1.0.0-rc.5", + "jsr:@cliffy/keycode@1.0.0-rc.5", + "jsr:@std/assert@1.0.0-rc.2", + "jsr:@std/fmt@~0.225.4", + "jsr:@std/io@~0.224.2", + "jsr:@std/path@1.0.0-rc.2", + "jsr:@std/text@1.0.0-rc.1" + ] + }, + "@cliffy/table@1.0.0-rc.5": { + "integrity": "2b3e1b4764bbb56b0c39aeba95bc0bb551d9bd4475fbb6d1ce368c08b7ef9eb3", + "dependencies": [ + "jsr:@std/cli@1.0.0-rc.2", + "jsr:@std/fmt@~0.225.4" + ] + }, + "@denosaurs/event@2.0.2": { + "integrity": "3310ba1a9e94dd60ccb09c6084fc818cc1cd50e543c56ef0c6199f1b89073392" + }, "@jotsr/delayed@2.1.1": { "integrity": "b636cc1ae8a2843412738f40c1cf5f117d909bf6986dbce7af945afd363b65b7" }, @@ -52,21 +106,45 @@ "@std/assert@0.224.0": { "integrity": "8643233ec7aec38a940a8264a6e3eed9bfa44e7a71cc6b3c8874213ff401967f" }, + "@std/assert@1.0.0-rc.2": { + "integrity": "0484eab1d76b55fca1c3beaff485a274e67dd3b9f065edcbe70030dfc0b964d3" + }, + "@std/assert@1.0.3": { + "integrity": "b0d03ce1ced880df67132eea140623010d415848df66f6aa5df76507ca7c26d8", + "dependencies": [ + "jsr:@std/internal@^1.0.2" + ] + }, "@std/async@0.224.2": { "integrity": "4d277d6e165df43d5e061ba0ef3edfddb8e8d558f5b920e3e6b1d2614b44d074" }, "@std/bytes@0.224.0": { "integrity": "a2250e1d0eb7d1c5a426f21267ab9bdeac2447fa87a3d0d1a467d3f7a6058e49" }, + "@std/bytes@1.0.2": { + "integrity": "fbdee322bbd8c599a6af186a1603b3355e59a5fb1baa139f8f4c3c9a1b3e3d57" + }, + "@std/cli@1.0.0-rc.2": { + "integrity": "97dfae82b9f0e189768ebfa7a5da53375955b94bad0a1804f8e3b73563b03787" + }, + "@std/collections@1.0.5": { + "integrity": "ab9eac23b57a0c0b89ba45134e61561f69f3d001f37235a248ed40be260c0c10" + }, "@std/dotenv@0.224.0": { "integrity": "d9234cdf551507dcda60abb6c474289843741d8c07ee8ce540c60f5c1b220a1d" }, + "@std/encoding@1.0.0-rc.2": { + "integrity": "160d7674a20ebfbccdf610b3801fee91cf6e42d1c106dd46bbaf46e395cd35ef" + }, "@std/fmt@0.217.0": { "integrity": "cb99f82500b8da20202fedfa8bb94dd0222e81f0494ed9087de20ee3d8a39a8d" }, "@std/fmt@0.224.0": { "integrity": "e20e9a2312a8b5393272c26191c0a68eda8d2c4b08b046bad1673148f1d69851" }, + "@std/fmt@0.225.6": { + "integrity": "aba6aea27f66813cecfd9484e074a9e9845782ab0685c030e453a8a70b37afc8" + }, "@std/fs@0.224.0": { "integrity": "52a5ec89731ac0ca8f971079339286f88c571a4d61686acf75833f03a89d8e69", "dependencies": [ @@ -79,6 +157,9 @@ "jsr:@std/async@^0.224.0" ] }, + "@std/internal@1.0.2": { + "integrity": "f4cabe2021352e8bfc24e6569700df87bf070914fc38d4b23eddd20108ac4495" + }, "@std/io@0.224.0": { "integrity": "0aff885d21d829c050b8a08b1d71b54aed5841aecf227f8d77e99ec529a11e8e", "dependencies": [ @@ -86,12 +167,21 @@ "jsr:@std/bytes@^0.224.0" ] }, + "@std/io@0.224.6": { + "integrity": "eefe034a370be34daf066c8634dd645635d099bb21eccf110f0bdc28d9040891", + "dependencies": [ + "jsr:@std/bytes@^1.0.2" + ] + }, "@std/path@0.224.0": { "integrity": "55bca6361e5a6d158b9380e82d4981d82d338ec587de02951e2b7c3a24910ee6", "dependencies": [ "jsr:@std/assert@^0.224.0" ] }, + "@std/path@1.0.0-rc.2": { + "integrity": "39f20d37a44d1867abac8d91c169359ea6e942237a45a99ee1e091b32b921c7d" + }, "@std/semver@0.224.0": { "integrity": "8da7354393dd9d2029278412107dbd5ca9dfb1fa240148d948eb2bfeb14f136a" }, @@ -109,6 +199,15 @@ "jsr:@std/assert@^0.217.0" ] }, + "@std/text@1.0.0-rc.1": { + "integrity": "34c722203e87ee12792c8d4a0cd2ee0e001341cbce75b860fc21be19d62232b0" + }, + "@std/toml@1.0.1": { + "integrity": "b55b407159930f338d384b1f8fd317c8e8a35e27ebb8946155f49e3a158d16c4", + "dependencies": [ + "jsr:@std/collections@^1.0.5" + ] + }, "@tsirysndr/fluent-az-pipelines@0.3.1": { "integrity": "50f25c5d21908debf3d7218c3ec4c0f987ed891a85a0b3e133e497492c57361b", "dependencies": [ @@ -168,6 +267,10 @@ "@noble/hashes": "@noble/hashes@1.4.0" } }, + "@types/node@18.16.19": { + "integrity": "sha512-IXl7o+R9iti9eBW4Wg2hx1xQDig183jj7YLn8F7udNceyfkbn1ZxmzZXuak20gR40D7pIkIY1kYGx5VIGbaHKA==", + "dependencies": {} + }, "base64-js@1.5.1": { "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", "dependencies": {} @@ -185,8 +288,8 @@ "node-fetch": "node-fetch@2.7.0" } }, - "dayjs@1.11.12": { - "integrity": "sha512-Rt2g+nTbLlDWZTwwrIXjy9MeiZmSDI375FvZs72ngxx8PDC6YXOeR3q5LAuPzjZQxhiWdRKac7RKV+YyQYfYIg==", + "dayjs@1.11.13": { + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", "dependencies": {} }, "docker-names-ts@1.2.4": { @@ -233,14 +336,6 @@ "integrity": "sha512-8VxGqAO1KFMkHYtQaVJgPse+Xz7DiGN1jVMeLGVGVuA5Jhxp3Ve5RO5U7JHS7miqk+eqt2bEkue0zb355HwL9A==", "dependencies": {} }, - "toml@3.0.0": { - "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", - "dependencies": {} - }, - "tomlify-j0.4@3.0.0": { - "integrity": "sha512-2Ulkc8T7mXJ2l0W476YC/A209PR38Nw8PuaCNtk9uI3t1zzFdGQeWYGQvmj2PZkVvRC/Yoi4xQKMRnWc/N29tQ==", - "dependencies": {} - }, "tr46@0.0.3": { "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", "dependencies": {} @@ -331,23 +426,6 @@ "https://deno.land/std@0.170.0/fmt/colors.ts": "03ad95e543d2808bc43c17a3dd29d25b43d0f16287fe562a0be89bf632454a12", "https://deno.land/std@0.189.0/fmt/colors.ts": "d67e3cd9f472535241a8e410d33423980bec45047e343577554d3356e1f0ef4e", "https://deno.land/std@0.189.0/streams/write_all.ts": "aec90152978581ea62d56bb53a5cbf487e6a89c902f87c5969681ffbdf32b998", - "https://deno.land/std@0.196.0/_util/os.ts": "d932f56d41e4f6a6093d56044e29ce637f8dcc43c5a90af43504a889cf1775e3", - "https://deno.land/std@0.196.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee", - "https://deno.land/std@0.196.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56", - "https://deno.land/std@0.196.0/console/_data.json": "cf2cc9d039a192b3adbfe64627167c7e6212704c888c25c769fc8f1709e1e1b8", - "https://deno.land/std@0.196.0/console/_rle.ts": "56668d5c44f964f1b4ff93f21c9896df42d6ee4394e814db52d6d13f5bb247c7", - "https://deno.land/std@0.196.0/console/unicode_width.ts": "10661c0f2eeab802d16b8b85ed8825bbc573991bbfb6affed32dc1ff994f54f9", - "https://deno.land/std@0.196.0/encoding/base64.ts": "144ae6234c1fbe5b68666c711dc15b1e9ee2aef6d42b3b4345bf9a6c91d70d0d", - "https://deno.land/std@0.196.0/fmt/colors.ts": "a7eecffdf3d1d54db890723b303847b6e0a1ab4b528ba6958b8f2e754cf1b3bc", - "https://deno.land/std@0.196.0/path/_constants.ts": "e49961f6f4f48039c0dfed3c3f93e963ca3d92791c9d478ac5b43183413136e0", - "https://deno.land/std@0.196.0/path/_interface.ts": "6471159dfbbc357e03882c2266d21ef9afdb1e4aa771b0545e90db58a0ba314b", - "https://deno.land/std@0.196.0/path/_util.ts": "d7abb1e0dea065f427b89156e28cdeb32b045870acdf865833ba808a73b576d0", - "https://deno.land/std@0.196.0/path/common.ts": "ee7505ab01fd22de3963b64e46cff31f40de34f9f8de1fff6a1bd2fe79380000", - "https://deno.land/std@0.196.0/path/glob.ts": "d479e0a695621c94d3fd7fe7abd4f9499caf32a8de13f25073451c6ef420a4e1", - "https://deno.land/std@0.196.0/path/mod.ts": "f065032a7189404fdac3ad1a1551a9ac84751d2f25c431e101787846c86c79ef", - "https://deno.land/std@0.196.0/path/posix.ts": "8b7c67ac338714b30c816079303d0285dd24af6b284f7ad63da5b27372a2c94d", - "https://deno.land/std@0.196.0/path/separator.ts": "0fb679739d0d1d7bf45b68dacfb4ec7563597a902edbaf3c59b50d5bcadd93b1", - "https://deno.land/std@0.196.0/path/win32.ts": "4fca292f8d116fd6d62f243b8a61bd3d6835a9f0ede762ba5c01afe7c3c0aa12", "https://deno.land/std@0.204.0/assert/assert.ts": "9a97dad6d98c238938e7540736b826440ad8c1c1e54430ca4c4e623e585607ee", "https://deno.land/std@0.204.0/assert/assertion_error.ts": "4d0bde9b374dfbcbe8ac23f54f567b77024fb67dbb1906a852d67fe050d42f56", "https://deno.land/std@0.204.0/path/_common/assert_path.ts": "061e4d093d4ba5aebceb2c4da3318bfe3289e868570e9d3a8e327d91c2958946", @@ -368,42 +446,6 @@ "https://deno.land/std@0.215.0/assert/assertion_error.ts": "9f689a101ee586c4ce92f52fa7ddd362e86434ffdf1f848e45987dc7689976b8", "https://deno.land/std@0.215.0/cli/parse_args.ts": "b24efc18e9cb4fab5d7daed7a04fa5edbdd5c7998b1e44d44aa9d85111817011", "https://deno.land/std@0.52.0/fmt/colors.ts": "ec9d653672a9a3c7b6eafe53c5bc797364a2db2dcf766ab649c1155fea7a80b2", - "https://deno.land/x/cliffy@v1.0.0-rc.3/_utils/distance.ts": "02af166952c7c358ac83beae397aa2fbca4ad630aecfcd38d92edb1ea429f004", - "https://deno.land/x/cliffy@v1.0.0-rc.3/ansi/ansi_escapes.ts": "193b3c3a4e520274bd8322ca4cab1c3ce38070bed1898cb2ade12a585dddd7c9", - "https://deno.land/x/cliffy@v1.0.0-rc.3/ansi/chain.ts": "eca61b1b64cad7b9799490c12c7aa5538d0f63ac65a73ddb6acac8b35f0a5323", - "https://deno.land/x/cliffy@v1.0.0-rc.3/ansi/cursor_position.ts": "caa008d29f7a904908bda514f9839bfbb7a93f2d5f5580501675b646d26a87ff", - "https://deno.land/x/cliffy@v1.0.0-rc.3/ansi/deps.ts": "f48ae5d066684793f4a203524db2a9fd61f514527934b458006f3e57363c0215", - "https://deno.land/x/cliffy@v1.0.0-rc.3/ansi/tty.ts": "155aacdcb7dc00f3f95352616a2415c622ffb88db51c5934e5d2e8341eab010b", - "https://deno.land/x/cliffy@v1.0.0-rc.3/keycode/_key_codes.ts": "917f0a2da0dbace08cf29bcfdaaa2257da9fe7e705fff8867d86ed69dfb08cfe", - "https://deno.land/x/cliffy@v1.0.0-rc.3/keycode/key_code.ts": "730fa675ca12fc2a99ba718aa8dbebb1f2c89afd47484e30ef3cb705ddfca367", - "https://deno.land/x/cliffy@v1.0.0-rc.3/keycode/mod.ts": "981b828bddada634e62a2a067b9d1592986180c4e920eb55e0a43cc085eb98ab", - "https://deno.land/x/cliffy@v1.0.0-rc.3/prompt/_figures.ts": "e22413ddd51bb271b6b861a058742e83aaa3f62c14e8162cb73ae6f047062f51", - "https://deno.land/x/cliffy@v1.0.0-rc.3/prompt/_generic_input.ts": "870dad97077582439cee26cb19aec123b4850376331338abdc64a91224733cdc", - "https://deno.land/x/cliffy@v1.0.0-rc.3/prompt/_generic_list.ts": "8b0bea4521b1e2f62c564e0d3764a63264043694f4228bb0bc0b63ce129ef33b", - "https://deno.land/x/cliffy@v1.0.0-rc.3/prompt/_generic_prompt.ts": "4c9d9cdeda749620a3f5332524df13d083e2d59b1ed90a003f43cd0991a75a10", - "https://deno.land/x/cliffy@v1.0.0-rc.3/prompt/_generic_suggestions.ts": "5e6ee1190b4dd5af261ae2ff0196dec7f1988ea9c41c6288cfaece293703002c", - "https://deno.land/x/cliffy@v1.0.0-rc.3/prompt/_utils.ts": "498ae639d7666599d612b615ee85de9103b3c3a913d5196f6b265072674258c7", - "https://deno.land/x/cliffy@v1.0.0-rc.3/prompt/checkbox.ts": "9cfd71f1e278d0ef76054be103d956b66995593902c149380d01b1a1647025f3", - "https://deno.land/x/cliffy@v1.0.0-rc.3/prompt/confirm.ts": "ff892331f6de281079421fe2f57f1d56acb38f28bc48678f87a3fc11ef4a5f7c", - "https://deno.land/x/cliffy@v1.0.0-rc.3/prompt/deps.ts": "2560142f070bb2668e2e8a74683c799461648b9aad01bbf36b3cad3851d712e6", - "https://deno.land/x/cliffy@v1.0.0-rc.3/prompt/input.ts": "81821244f895cc4db32c2511c17e21fb48fd7606e300605aeb2a231ab1680544", - "https://deno.land/x/cliffy@v1.0.0-rc.3/prompt/list.ts": "e5d3e1a6d931b9736d03eec2425fb7b4d2b8d1461a84e210b4787edda414dca4", - "https://deno.land/x/cliffy@v1.0.0-rc.3/prompt/mod.ts": "f8789193742daf3aba93b543a2ea099383284d60fcccc03567102e28c0d61927", - "https://deno.land/x/cliffy@v1.0.0-rc.3/prompt/number.ts": "5421bf1b6411a6f02c44da4e867f19e02315450769e0feacab3c1c88cc1b06d6", - "https://deno.land/x/cliffy@v1.0.0-rc.3/prompt/prompt.ts": "f10e1c8a0c2ca093a485f7f1156342210b27a8cffc96fe0b4cff60007cabab30", - "https://deno.land/x/cliffy@v1.0.0-rc.3/prompt/secret.ts": "cece271c7ce01e12b249c31c2f9cea9e53b6e6be7621a478dac902bd8f288b61", - "https://deno.land/x/cliffy@v1.0.0-rc.3/prompt/select.ts": "c10902aeaca02a55d9b846934958dd166ee39c741faebdaa9800689e402186cf", - "https://deno.land/x/cliffy@v1.0.0-rc.3/prompt/toggle.ts": "028f80de31750e7b5479727a64b4878f090ecd783fe3bb0d286e2e1c29f0eee3", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/_layout.ts": "e4a518da28333de95ad791208b9930025987c8b93d5f8b7f30b377b3e26b24e1", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/_utils.ts": "fd48d1a524a42e72aa3ad2eec858a92f5a00728d306c7e8436fba6c34314fee6", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/border.ts": "5c6e9ef5078c6930169aacb668b274bdbb498461c724a7693ac9270fe9d3f5d5", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/cell.ts": "1ffabd43b6b7fddfac9625cb0d015532e144702a9bfed03b358b79375115d06b", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/column.ts": "cf14009f2cb14bad156f879946186c1893acdc6a2fee6845db152edddb6a2714", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/consume_words.ts": "456e75755fdf6966abdefb8b783df2855e2a8bad6ddbdf21bd748547c5fc1d4b", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/deps.ts": "1226c4d39d53edc81d7c3e661fb8a79f2e704937c276c60355cd4947a0fe9153", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/mod.ts": "40f148428acbfffa270f7077c403b3893797d9e454a74ccb41a8434367351326", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/row.ts": "79eb1468aafdd951e5963898cdafe0752d4ab4c519d5f847f3d8ecb8fe857d4f", - "https://deno.land/x/cliffy@v1.0.0-rc.3/table/table.ts": "298671e72e61f1ab18b42ae36643181993f79e29b39dc411fdc6ffd53aa04684", "https://deno.land/x/dir@1.5.2/cache_dir/mod.ts": "8a82889db79c547fbbd3536c9c964047657b19fb59365c5fa59afc46082f9fe5", "https://deno.land/x/dir@1.5.2/config_dir/mod.ts": "d16ca6f949c3e42ed23f942261d2482f340dd6c73542740f57c89abeaa83ea3f", "https://deno.land/x/dir@1.5.2/data_dir/mod.ts": "7d17c6d9e775974245e0456c8f83f751c41c792c06020d12ca1ca69a0ce4e671", diff --git a/deps.ts b/deps.ts index 277da3e..de9cc00 100644 --- a/deps.ts +++ b/deps.ts @@ -17,12 +17,8 @@ export { z } from "https://deno.land/x/zod@v3.22.2/mod.ts"; export { decompress } from "https://deno.land/x/zip@v1.2.5/mod.ts"; export { existsSync } from "jsr:@std/fs@0.224.0/exists"; export { load } from "jsr:@std/dotenv@0.224.0"; -export { Secret } from "https://deno.land/x/cliffy@v1.0.0-rc.3/prompt/secret.ts"; -export { - Confirm, - Input, - prompt, -} from "https://deno.land/x/cliffy@v1.0.0-rc.3/prompt/mod.ts"; +export { Secret } from "jsr:@cliffy/prompt@1.0.0-rc.5/secret"; +export { Confirm, Input, prompt } from "jsr:@cliffy/prompt@1.0.0-rc.5"; import dir from "https://deno.land/x/dir@1.5.2/mod.ts"; export { dir }; export { walk, walkSync } from "jsr:@std/fs@0.224.0/walk"; @@ -54,19 +50,12 @@ export { dayjs }; import { Buffer } from "npm:buffer"; export { Buffer }; export { mergeReadableStreams } from "jsr:@std/streams@0.224.0"; -export { - Cell, - Table, -} from "https://deno.land/x/cliffy@v1.0.0-rc.3/table/mod.ts"; +export { Cell, Table } from "jsr:@cliffy/table@1.0.0-rc.5"; export { TerminalSpinner, SpinnerTypes, } from "https://deno.land/x/spinners@v1.1.2/mod.ts"; export { readAllSync } from "jsr:@std/io@0.224.0"; -import * as toml from "npm:toml@3.0.0"; -export { toml }; -import tomlify from "npm:tomlify-j0.4@3.0.0"; -export { tomlify }; export { serve } from "jsr:@std/http@0.224.0/server"; export { createYoga } from "https://esm.sh/graphql-yoga@5.1.1?external=graphql"; import SchemaBuilder from "https://esm.sh/*@pothos/core@3.41.1"; @@ -87,3 +76,7 @@ export { export { AzurePipeline } from "jsr:@tsirysndr/fluent-az-pipelines@0.3.1"; export { BuildSpec } from "jsr:@tsirysndr/fluent-codepipeline@0.3"; export { ClientError, GraphQLClient, gql } from "npm:graphql-request@6.1.0"; +import * as toml from "jsr:@std/toml"; +export { toml }; +export { assertEquals, assertObjectMatch } from "jsr:@std/assert"; +export { EventEmitter } from "jsr:@denosaurs/event"; diff --git a/fixtures/android.fluentci.toml b/fixtures/android.fluentci.toml new file mode 100644 index 0000000..5c25eb6 --- /dev/null +++ b/fixtures/android.fluentci.toml @@ -0,0 +1,3 @@ +[[steps]] +command = "fluentci run --wasm android assemble_release" +name = "Run gradle build" diff --git a/fixtures/bazel.fluentci.toml b/fixtures/bazel.fluentci.toml new file mode 100644 index 0000000..4db42c1 --- /dev/null +++ b/fixtures/bazel.fluentci.toml @@ -0,0 +1,7 @@ +[[steps]] +command = "fluentci run --wasm bazel test //..." +name = "Run tests" + +[[steps]] +command = "fluentci run --wasm bazel build //..." +name = "Build" diff --git a/fixtures/buck.fluentci.toml b/fixtures/buck.fluentci.toml new file mode 100644 index 0000000..eaf121e --- /dev/null +++ b/fixtures/buck.fluentci.toml @@ -0,0 +1,7 @@ +[[steps]] +command = ["fluentci run --wasm buck test //..."] +name = "Run tests" + +[[steps]] +command = ["fluentci run --wasm buck build //..."] +name = "Build" diff --git a/fixtures/cmake.fluentci.toml b/fixtures/cmake.fluentci.toml new file mode 100644 index 0000000..48c06cb --- /dev/null +++ b/fixtures/cmake.fluentci.toml @@ -0,0 +1,13 @@ +[[steps]] +command = [ + "fluentci run --wasm cmake generate", + "fluentci run --wasm make test", +] +name = "Run tests" + +[[steps]] +command = [ + "fluentci run --wasm cmake generate", + "fluentci run --wasm cmake make", +] +name = "Build" diff --git a/fixtures/cypress.fluentci.toml b/fixtures/cypress.fluentci.toml new file mode 100644 index 0000000..68d8f37 --- /dev/null +++ b/fixtures/cypress.fluentci.toml @@ -0,0 +1,11 @@ +[[steps]] +command = ["fluentci run --wasm bun install"] +name = "Install dependencies" + +[[steps]] +command = [ + "fluentci run --wasm cypress verify", + "fluentci run --wasm cypress info", + "fluentci run --wasm bun run test:ci", +] +name = "Run e2e tests" diff --git a/fixtures/deno.fluentci.toml b/fixtures/deno.fluentci.toml new file mode 100644 index 0000000..0e731fa --- /dev/null +++ b/fixtures/deno.fluentci.toml @@ -0,0 +1,13 @@ +[[steps]] +command = [ + "fluentci run --wasm postgres start", + "fluentci run --wasm deno task test", +] +env = ["POSTGRES_USER=postgres", "POSTGRES_DB=demo"] +name = "Run tests" + +[[steps]] +command = [ + "fluentci run --wasm deno compile -A --target x86_64-unknown-linux-gnu --output=app main.ts", +] +name = "Compile" diff --git a/fixtures/elixir-phoenix.fluentci.toml b/fixtures/elixir-phoenix.fluentci.toml new file mode 100644 index 0000000..c5773f5 --- /dev/null +++ b/fixtures/elixir-phoenix.fluentci.toml @@ -0,0 +1,20 @@ +[[steps]] +command = ["fluentci run --wasm mariadb start"] +env = [ + "MARIADB_USER=user", + "MARIADB_PASSWORD=password", + "MARIADB_DATABASE=example_test", +] +name = "Start MariaDB" + +[[steps]] +command = [ + "fluentci run --wasm elixir test", + "fluentci run --wasm elixir compile", +] +env = [ + "MYSQL_DATABASE=example_test", + "MYSQL_USER=root", + "MYSQL_HOST=127.0.0.1", +] +name = "Run tests" diff --git a/fixtures/fastlane.fluentci.toml b/fixtures/fastlane.fluentci.toml new file mode 100644 index 0000000..667d96c --- /dev/null +++ b/fixtures/fastlane.fluentci.toml @@ -0,0 +1,10 @@ +[[steps]] +command = ["fluentci run --wasm android setup"] +name = "Setup Android SDK" + +[[steps]] +command = [ + "fluentci run --wasm bun install", + "fluentci run --wasm fastlane android buildRelease", +] +name = "Build" diff --git a/fixtures/flutter.fluentci.toml b/fixtures/flutter.fluentci.toml new file mode 100644 index 0000000..f50cdb3 --- /dev/null +++ b/fixtures/flutter.fluentci.toml @@ -0,0 +1,10 @@ +[[steps]] +command = [ + "fluentci run --wasm flutter code_quality", + "fluentci run --wasm flutter test", +] +name = "Run tests" + +[[steps]] +command = ["fluentci run --wasm flutter build apk --release"] +name = "Build" diff --git a/fixtures/gleam.fluentci.toml b/fixtures/gleam.fluentci.toml new file mode 100644 index 0000000..4c65cc6 --- /dev/null +++ b/fixtures/gleam.fluentci.toml @@ -0,0 +1,7 @@ +[[steps]] +command = ["fluentci run --wasm gleam test"] +name = "Run tests" + +[[steps]] +command = ["fluentci run --wasm gleam build"] +name = "Build" diff --git a/fixtures/go.fluentci.toml b/fixtures/go.fluentci.toml new file mode 100644 index 0000000..aebf1a6 --- /dev/null +++ b/fixtures/go.fluentci.toml @@ -0,0 +1,27 @@ +[[steps]] +command = ["fluentci run --wasm pkgx install go"] +name = "Setup go" + +[[steps]] +command = ["go get", "go build -o ./bin/main"] +name = "go get & build" + +[[steps]] +command = ["gofmt main.go | diff --ignore-tab-expansion main.go -"] +name = "Check code style" + +[[steps]] +command = [ + "fluentci run --wasm postgres start", + "go install gotest.tools/gotestsum@latest", + "PATH=$HOME/go/bin:$PATH gotestsum --junitfile junit.xml ./...", +] +env = ["POSTGRES_USER=postgres", "POSTGRES_DB=s2"] +name = "Run tests" + +[[steps]] +command = [ + "./bin/main 8001 &", + "curl --silent localhost:8001/time | grep 'The current time is'", +] +name = "Test web server" diff --git a/fixtures/java-spring.fluentci.toml b/fixtures/java-spring.fluentci.toml new file mode 100644 index 0000000..00b5179 --- /dev/null +++ b/fixtures/java-spring.fluentci.toml @@ -0,0 +1,28 @@ +[[steps]] +command = ["fluentci run --wasm java setup zulu-17.46.16"] +name = "Setup Java" + +[[steps]] +command = ["fluentci run --wasm maven setup"] +name = "Setup maven" + +[[steps]] +command = ["mvn -q package jmeter:configure -Dmaven.test.skip-true"] +env = ["JAVA_HOME=$HOME/.local/share/mise/installs/java/zulu-17.46.16"] +name = "Build" + +[[steps]] +command = ["java -version", "mvn -q test-compile -Dmaven.test.skip=true"] +env = ["JAVA_HOME=$HOME/.local/share/mise/installs/java/zulu-17.46.16"] +name = "Run tests" + +[[steps]] +command = [ + "java -version", + "java -jar target/spring-pipeline-demo.jar > /dev/null &", + "sleep 20", + "mvn -q jmeter:jmeter", + "mvn jmeter:results", +] +env = ["JAVA_HOME=$HOME/.local/share/mise/installs/java/zulu-17.46.16"] +name = "Performance tests" diff --git a/fixtures/javascript.fluentci.toml b/fixtures/javascript.fluentci.toml new file mode 100644 index 0000000..5253027 --- /dev/null +++ b/fixtures/javascript.fluentci.toml @@ -0,0 +1,42 @@ +[package] +authors = ["Tsiry Sandratraina "] +description = "" +license = "MIT" +name = "fluentci-demo-javascript" +version = "0.1.0" + +[[steps]] +command = ["fluentci run --wasm bun run lint"] +name = "Client lint" +working_directory = "src/client" + +[[steps]] +command = ["fluentci run --wasm bun run lint"] +name = "Server lint" +working_directory = "src/server" + +[[steps]] +command = ["fluentci run --wasm bun run test"] +env = ["CI=true", "NODE_ENV=test"] +name = "Client Unit Tests" +working_directory = "src/client" + +[[steps]] +command = ["fluentci run --wasm bun run test"] +env = ["CI=true", "NODE_ENV=test"] +name = "Server Unit Tests" +working_directory = "src/server" + +[[steps]] +command = [ + "cd src/client && fluentci run --wasm cypress install && cd ../.. && fluentci run --wasm . e2e", +] +name = "End to End Tests" + +[[steps]] +command = [ + "fluentci run --wasm postgres start", + "pkgx psql ---host=localhost -d postgres -U `whoami` -c 'CREATE DATABASE test;'", + "fluentci run --wasm . server_e2e", +] +name = "End to End Tests (Server)" diff --git a/fixtures/kotlin.fluentci.toml b/fixtures/kotlin.fluentci.toml new file mode 100644 index 0000000..8569695 --- /dev/null +++ b/fixtures/kotlin.fluentci.toml @@ -0,0 +1,7 @@ +[[steps]] +command = ["fluentci run --wasm gradle test"] +name = "test" + +[[steps]] +command = ["fluentci run --wasm gradle build"] +name = "build" diff --git a/fixtures/php-laravel.fluentci.toml b/fixtures/php-laravel.fluentci.toml new file mode 100644 index 0000000..9da8ced --- /dev/null +++ b/fixtures/php-laravel.fluentci.toml @@ -0,0 +1,17 @@ +[[steps]] +command = ["fluentci run --wasm mariadb start"] +env = [ + "MARIADB_USER=user", + "MARIADB_PASSWORD=password", + "MARIADB_DATABASE=laravel", +] +name = "Start MariaDB" + +[[steps]] +command = ["fluentci run --wasm laravel test"] +env = [ + "MARIADB_DATABASE=laravel", + "MARIADB_USER=user", + "MARIADB_PASSWORD=password", +] +name = "Run tests" diff --git a/fixtures/php.fluentci.toml b/fixtures/php.fluentci.toml new file mode 100644 index 0000000..e685aa7 --- /dev/null +++ b/fixtures/php.fluentci.toml @@ -0,0 +1,6 @@ +[[steps]] +command = [ + "fluentci run --wasm php composer_install --no-interaction", + "fluentci run --wasm php test", +] +name = "Run tests" diff --git a/fixtures/playwright.fluentci.toml b/fixtures/playwright.fluentci.toml new file mode 100644 index 0000000..5b97a19 --- /dev/null +++ b/fixtures/playwright.fluentci.toml @@ -0,0 +1,11 @@ +[[steps]] +command = ["fluentci run --wasm bun install"] +name = "Install dependencies" + +[[steps]] +command = [ + "fluentci run --wasm playwright install --with-deps", + "fluentci run --wasm playwright test -j $(nproc)", +] +env = ["CI=true"] +name = "Run playwright tests" diff --git a/fixtures/python-django.fluentci.toml b/fixtures/python-django.fluentci.toml new file mode 100644 index 0000000..344e3a8 --- /dev/null +++ b/fixtures/python-django.fluentci.toml @@ -0,0 +1,20 @@ + +[[steps]] +command = ["fluentci run --wasm mariadb start"] +env = [ + "MARIADB_DATABSE=todo", + "MARIADB_USER=user", + "MARIADB_PASSWORD=testrootpass", +] +name = "Start MariaDB" + +[[steps]] +command = ["fluentci run --wasm django test"] +env = [ + "MARIADB_DATABSE=todo", + "MARIADB_USER=user", + "MARIADB_PASSWORD=testrootpass", + "MARIADB_ROOT_PASSWORD=root", + "MARIADB_HOST=127.0.0.1", +] +name = "Run tests" diff --git a/fixtures/python-flask.fluentci.toml b/fixtures/python-flask.fluentci.toml new file mode 100644 index 0000000..921620b --- /dev/null +++ b/fixtures/python-flask.fluentci.toml @@ -0,0 +1,14 @@ + +[[steps]] +command = ["fluentci run --wasm mongo start"] +name = "Start MongoDB" + +[[steps]] +command = [ + "fluentci run --wasm devbox run pip install -r requirements.txt", + "fluentci run --wasm devbox run python run.py &", + "sleep 2", + "fluentci run --wasm devbox run python -m unittest", +] +env = ["DB=mongodb://localhost:27017/tasks", "PORT=5000"] +name = "Run tests" diff --git a/fixtures/react-native.fluentci.toml b/fixtures/react-native.fluentci.toml new file mode 100644 index 0000000..cc4d709 --- /dev/null +++ b/fixtures/react-native.fluentci.toml @@ -0,0 +1,8 @@ +[[steps]] +command = ["fluentci run --wasm bun install"] +name = "Install dependencies" + +[[steps]] +command = ["fluentci run --wasm android assemble_release"] +name = "Run gradle assemble" +working_directory = "android" diff --git a/fixtures/ruby-on-rails.fluentci.toml b/fixtures/ruby-on-rails.fluentci.toml new file mode 100644 index 0000000..4ed43c1 --- /dev/null +++ b/fixtures/ruby-on-rails.fluentci.toml @@ -0,0 +1,19 @@ +[[steps]] +command = ["fluentci run --wasm postgres start"] +env = ["POSTGRES_USER=postgres", "POSTGRES_DB=demo_rails_test"] +name = "Start Postgres" + +[[steps]] +command = ["fluentci run --wasm ruby bundle_exec rubocop"] +env = ["RUBY_VERSION=3.1.4"] +name = "Check style + security" + +[[steps]] +command = [ + "fluentci run --wasm ruby bundle_exec rails db:migrate", + "fluentci run --wasm ruby bundle_exec rails db:seed", + "fluentci run --wasm ruby bundle_exec rails test", + "fluentci run --wasm ruby bundle_exec rails spec", +] +env = ["RAILS_ENV=test"] +name = "Run tests" diff --git a/fixtures/ruby.fluentci.toml b/fixtures/ruby.fluentci.toml new file mode 100644 index 0000000..19bd1a4 --- /dev/null +++ b/fixtures/ruby.fluentci.toml @@ -0,0 +1,3 @@ +[[steps]] +command = ["fluentci run --wasm ruby bundle_exec rspec"] +name = "Run tests" diff --git a/fixtures/rust.fluentci.toml b/fixtures/rust.fluentci.toml new file mode 100644 index 0000000..c362757 --- /dev/null +++ b/fixtures/rust.fluentci.toml @@ -0,0 +1,24 @@ +[[steps]] +command = ["fluentci run --wasm rust setup"] +name = "Setup Rust" + +[[steps]] +command = [ + "fluentci run --wasm postgres start", + "curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash", + "cargo-binstall sqlx-cli -y", + "sqlx migrate run", + "cargo sqlx prepare", + "cargo test", +] +env = [ + "POSTGRES_USER=postgres", + "POSTGRES_DB=demo", + "DATABASE_URL=postgres://postgres@localhost/demo", +] +name = "Run tests" + +[[steps]] +command = ["fluentci run --wasm rust build"] +env = ["DATABASE_URL=postgres://postgres@localhost/demo"] +name = "Run build" diff --git a/fixtures/swift.fluentci.toml b/fixtures/swift.fluentci.toml new file mode 100644 index 0000000..a2f85b0 --- /dev/null +++ b/fixtures/swift.fluentci.toml @@ -0,0 +1,7 @@ +[[steps]] +command = ["fluentci run --wasm swift test"] +name = "Run tests" + +[[steps]] +command = ["fluentci run --wasm swift build"] +name = "Build" diff --git a/fixtures/symfony.fluentci.toml b/fixtures/symfony.fluentci.toml new file mode 100644 index 0000000..b1cd935 --- /dev/null +++ b/fixtures/symfony.fluentci.toml @@ -0,0 +1,11 @@ +[[steps]] +command = [ + "fluentci run --wasm symfony container_lint", + "fluentci run --wasm symfony doctrine_lint", + "fluentci run --wasm symfony phpstan", + "fluentci run --wasm symfony phpunit", + "fluentci run --wasm symfony twig_lint", + "fluentci run --wasm symfony xliff_lint", + "fluentci run --wasm symfony yaml_lint", +] +name = "Run lint checks and tests" diff --git a/fixtures/zig.fluentci.toml b/fixtures/zig.fluentci.toml new file mode 100644 index 0000000..9f1b1b5 --- /dev/null +++ b/fixtures/zig.fluentci.toml @@ -0,0 +1,7 @@ +[[steps]] +command = ["fluentci run --wasm zig test"] +name = "test" + +[[steps]] +command = ["fluentci run --wasm zig build"] +name = "build" diff --git a/src/cmd/agent.ts b/src/cmd/agent.ts index 030bcfe..1a4416a 100644 --- a/src/cmd/agent.ts +++ b/src/cmd/agent.ts @@ -360,10 +360,11 @@ async function executeActions( `fluentci run ${action.use_wasm ? "--wasm" : ""} ${ action.plugin } ${cmd}`, - cwd, + action.working_directory ? `${cwd}/${action.working_directory}` : cwd, jobs[currentActionIndex].job_id, logger, - clientId + clientId, + action.env === null ? undefined : action.env ); logs.push(...result.logs); @@ -478,7 +479,8 @@ async function spawn( cwd = Deno.cwd(), jobId: string, logger: Logger, - clientId: string + clientId: string, + env?: Record ) { const logs: Log[] = []; const child = new Deno.Command("bash", { @@ -486,6 +488,7 @@ async function spawn( stdout: "piped", stderr: "piped", cwd, + env, }).spawn(); const writableStdoutStream = new WritableStream({ diff --git a/src/cmd/init.ts b/src/cmd/init.ts index 385665d..2190fa2 100644 --- a/src/cmd/init.ts +++ b/src/cmd/init.ts @@ -9,7 +9,6 @@ import { green, _, toml, - tomlify, } from "../../deps.ts"; import { directoryExists } from "../utils.ts"; import { extractVersion } from "../utils.ts"; @@ -373,7 +372,7 @@ async function overrideCargoToml(infos: Record, path = ".") { await Deno.writeFile( `${path}/Cargo.toml`, - new TextEncoder().encode(tomlify.toToml(config, { space: 2 })) + new TextEncoder().encode(toml.stringify(config)) ); } @@ -400,7 +399,7 @@ async function overrideFluentciToml( await Deno.writeFile( `${path}/fluentci.toml`, - new TextEncoder().encode(tomlify.toToml(config, { space: 2 })) + new TextEncoder().encode(toml.stringify(config)) ); } diff --git a/src/cmd/server.ts b/src/cmd/server.ts index 67edd3a..7d51438 100644 --- a/src/cmd/server.ts +++ b/src/cmd/server.ts @@ -17,6 +17,7 @@ function server({ port }: { port?: number }) { projects, runs, }, + runs: new Map(), }; }, }); diff --git a/src/cmd/studio.ts b/src/cmd/studio.ts index 51ff57a..d9b260d 100644 --- a/src/cmd/studio.ts +++ b/src/cmd/studio.ts @@ -29,6 +29,7 @@ async function studio({ port }: { port?: number }) { projects, runs, }, + runs: new Map(), }; }, }); diff --git a/src/consts.ts b/src/consts.ts index 54d72e5..09d8042 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -1,5 +1,5 @@ import { dir } from "../deps.ts"; -export const VERSION = "0.15.9"; +export const VERSION = "0.16.0"; export const BASE_URL = "https://api.fluentci.io/v1"; diff --git a/src/git.ts b/src/git.ts index 15447e4..829a1d0 100644 --- a/src/git.ts +++ b/src/git.ts @@ -30,3 +30,17 @@ export async function getCommitInfos(cwd = Deno.cwd()) { author: new TextDecoder().decode(author).trim(), }; } + +export async function cloneRepository( + url: string, + cwd = Deno.cwd() +): Promise { + const status = await new Deno.Command("git", { + args: ["clone", url], + stdin: "inherit", + stdout: "inherit", + stderr: "inherit", + cwd, + }).spawn().status; + return status.success; +} diff --git a/src/logos.ts b/src/logos.ts new file mode 100644 index 0000000..b5476e1 --- /dev/null +++ b/src/logos.ts @@ -0,0 +1,51 @@ +export default { + android: + "https://upload.wikimedia.org/wikipedia/commons/3/31/Android_robot_head.svg", + fastlane: + "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github/assets/fastlane.png", + elixir: + "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github/assets/elixir.svg", + ruby: "https://avatars.githubusercontent.com/u/210414", + phoenix: "https://avatars.githubusercontent.com/u/6510388", + laravel: "https://avatars.githubusercontent.com/u/958072", + javascript: "https://devicons.railway.app/i/javascript.svg", + flutter: + "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github/assets/flutter-original.svg", + rust: "https://avatars.githubusercontent.com/u/5430905", + cypress: "https://avatars.githubusercontent.com/u/8908513", + playwright: "https://playwright.dev/img/playwright-logo.svg", + go: "https://avatars.githubusercontent.com/u/4314092", + zig: "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github/assets/zig-original.svg", + bazel: + "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github/assets/bazel.svg", + gleam: "https://avatars.githubusercontent.com/u/36161205", + php: "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github/assets/php-plain.svg", + deno: "https://avatars.githubusercontent.com/u/42048915", + buck: "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github@main/assets/buck.svg", + cmake: "https://upload.wikimedia.org/wikipedia/commons/1/13/Cmake.svg", + kotlin: "https://devicons.railway.app/i/kotlin.svg", + spring: "https://devicons.railway.app/i/spring.svg", + django: "https://avatars.githubusercontent.com/u/27804", + swift: + "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github/assets/swift.svg", + flask: "https://devicons.railway.app/i/flask-light.svg", + react_native: "https://devicons.railway.app/i/react.svg", + symfony: "https://avatars.githubusercontent.com/u/143937", + sinatra: "https://avatars.githubusercontent.com/u/8312", + bun: "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github/assets/bun.svg", + mariadb: "https://avatars.githubusercontent.com/u/4739304", + mysql: "https://upload.wikimedia.org/wikipedia/fr/6/62/MySQL.svg", + postgres: + "https://upload.wikimedia.org/wikipedia/commons/2/29/Postgresql_elephant.svg", + redis: "https://avatars.githubusercontent.com/u/1529926", + nginx: "https://upload.wikimedia.org/wikipedia/commons/c/c5/Nginx_logo.svg", + caddy: + "https://raw.githubusercontent.com/caddyserver/website/07c51663ab3cf37c8831eefeb64383a10af3a4a5/src/resources/images/favicon.png", + dragonflydb: "https://avatars.githubusercontent.com/u/104819355", + temporal: "https://avatars.githubusercontent.com/u/56493103", + rabbitmq: "https://avatars.githubusercontent.com/u/96669", + meilisearch: "https://avatars.githubusercontent.com/u/43250847", + typesense: "https://avatars.githubusercontent.com/u/19822348", + mongo: "https://avatars.githubusercontent.com/u/45120", + gradle: "https://avatars.githubusercontent.com/u/124156", +} as Record; diff --git a/src/parser/config.test.ts b/src/parser/config.test.ts new file mode 100644 index 0000000..2d99f4d --- /dev/null +++ b/src/parser/config.test.ts @@ -0,0 +1,779 @@ +import { assertEquals } from "../../deps.ts"; +import { parseConfig } from "./config.ts"; + +Deno.test("config - android.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/android.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + name: "Run gradle build", + commands: "assemble_release", + enabled: true, + logo: "https://upload.wikimedia.org/wikipedia/commons/3/31/Android_robot_head.svg", + plugin: "android", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - bazel.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/bazel.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + name: "Run tests", + commands: "test //...", + enabled: true, + logo: "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github/assets/bazel.svg", + plugin: "bazel", + use_wasm: true, + }, + { + name: "Build", + commands: "build //...", + enabled: true, + logo: "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github/assets/bazel.svg", + plugin: "bazel", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - buck.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/buck.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + name: "Run tests", + commands: "test //...", + enabled: true, + logo: "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github@main/assets/buck.svg", + plugin: "buck", + use_wasm: true, + }, + { + name: "Build", + commands: "build //...", + enabled: true, + logo: "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github@main/assets/buck.svg", + plugin: "buck", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - cmake.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/cmake.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + name: "Run tests", + commands: + 'bash "fluentci run --wasm cmake generate"\n' + + 'bash "fluentci run --wasm make test"', + enabled: true, + plugin: "shell", + use_wasm: true, + }, + { + name: "Build", + commands: + 'bash "fluentci run --wasm cmake generate"\n' + + 'bash "fluentci run --wasm cmake make"', + enabled: true, + plugin: "shell", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - cypress.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/cypress.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + commands: "install", + logo: "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github/assets/bun.svg", + name: "Install dependencies", + enabled: true, + plugin: "bun", + use_wasm: true, + }, + { + name: "Run e2e tests", + commands: + 'bash "fluentci run --wasm cypress verify"\n' + + 'bash "fluentci run --wasm cypress info"\n' + + 'bash "fluentci run --wasm bun run test:ci"', + enabled: true, + plugin: "shell", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - deno.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/deno.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + commands: + 'bash "fluentci run --wasm postgres start"\n' + + 'bash "fluentci run --wasm deno task test"', + enabled: true, + env: { POSTGRES_USER: "postgres", POSTGRES_DB: "demo" }, + name: "Run tests", + plugin: "shell", + use_wasm: true, + }, + { + commands: + "compile -A --target x86_64-unknown-linux-gnu --output=app main.ts", + enabled: true, + logo: "https://avatars.githubusercontent.com/u/42048915", + name: "Compile", + plugin: "deno", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - elixir-phoenix.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/elixir-phoenix.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + commands: "start", + enabled: true, + env: { + MARIADB_USER: "user", + MARIADB_PASSWORD: "password", + MARIADB_DATABASE: "example_test", + }, + logo: "https://avatars.githubusercontent.com/u/4739304", + name: "Start MariaDB", + plugin: "mariadb", + use_wasm: true, + }, + { + commands: + 'bash "fluentci run --wasm elixir test"\n' + + 'bash "fluentci run --wasm elixir compile"', + enabled: true, + env: { + MYSQL_DATABASE: "example_test", + MYSQL_USER: "root", + MYSQL_HOST: "127.0.0.1", + }, + name: "Run tests", + plugin: "shell", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - fastlane.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/fastlane.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + commands: "setup", + enabled: true, + logo: "https://upload.wikimedia.org/wikipedia/commons/3/31/Android_robot_head.svg", + name: "Setup Android SDK", + plugin: "android", + use_wasm: true, + }, + { + commands: + 'bash "fluentci run --wasm bun install"\n' + + 'bash "fluentci run --wasm fastlane android buildRelease"', + enabled: true, + name: "Build", + plugin: "shell", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - flutter.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/flutter.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + commands: + 'bash "fluentci run --wasm flutter code_quality"\n' + + 'bash "fluentci run --wasm flutter test"', + enabled: true, + name: "Run tests", + plugin: "shell", + use_wasm: true, + }, + { + commands: "build apk --release", + enabled: true, + logo: "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github/assets/flutter-original.svg", + name: "Build", + plugin: "flutter", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - gleam.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/gleam.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + commands: "test", + enabled: true, + logo: "https://avatars.githubusercontent.com/u/36161205", + name: "Run tests", + plugin: "gleam", + use_wasm: true, + }, + { + commands: "build", + enabled: true, + logo: "https://avatars.githubusercontent.com/u/36161205", + name: "Build", + plugin: "gleam", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - go.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/go.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + commands: "install go", + enabled: true, + name: "Setup go", + plugin: "pkgx", + use_wasm: true, + }, + { + commands: 'bash "go get"\nbash "go build -o ./bin/main"', + enabled: true, + name: "go get & build", + plugin: "shell", + use_wasm: true, + }, + { + commands: 'bash "gofmt main.go | diff --ignore-tab-expansion main.go -"', + enabled: true, + name: "Check code style", + plugin: "shell", + use_wasm: true, + }, + { + commands: + 'bash "fluentci run --wasm postgres start"\n' + + 'bash "go install gotest.tools/gotestsum@latest"\n' + + 'bash "PATH=$HOME/go/bin:$PATH gotestsum --junitfile junit.xml ./..."', + enabled: true, + env: { + POSTGRES_DB: "s2", + POSTGRES_USER: "postgres", + }, + name: "Run tests", + plugin: "shell", + use_wasm: true, + }, + { + commands: + 'bash "./bin/main 8001 &"\n' + + "bash \"curl --silent localhost:8001/time | grep 'The current time is'\"", + enabled: true, + name: "Test web server", + plugin: "shell", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - java-spring.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/java-spring.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + commands: "setup zulu-17.46.16", + enabled: true, + name: "Setup Java", + plugin: "java", + use_wasm: true, + }, + { + commands: "setup", + enabled: true, + name: "Setup maven", + plugin: "maven", + use_wasm: true, + }, + { + commands: 'bash "mvn -q package jmeter:configure -Dmaven.test.skip-true"', + enabled: true, + env: { + JAVA_HOME: "$HOME/.local/share/mise/installs/java/zulu-17.46.16", + }, + name: "Build", + plugin: "shell", + use_wasm: true, + }, + { + commands: + 'bash "java -version"\nbash "mvn -q test-compile -Dmaven.test.skip=true"', + enabled: true, + env: { + JAVA_HOME: "$HOME/.local/share/mise/installs/java/zulu-17.46.16", + }, + name: "Run tests", + plugin: "shell", + use_wasm: true, + }, + { + commands: + 'bash "java -version"\n' + + 'bash "java -jar target/spring-pipeline-demo.jar > /dev/null &"\n' + + 'bash "sleep 20"\n' + + 'bash "mvn -q jmeter:jmeter"\n' + + 'bash "mvn jmeter:results"', + enabled: true, + env: { + JAVA_HOME: "$HOME/.local/share/mise/installs/java/zulu-17.46.16", + }, + name: "Performance tests", + plugin: "shell", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - javascript.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/javascript.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + commands: "run lint", + enabled: true, + logo: "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github/assets/bun.svg", + name: "Client lint", + plugin: "bun", + use_wasm: true, + working_directory: "src/client", + }, + { + commands: "run lint", + enabled: true, + logo: "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github/assets/bun.svg", + name: "Server lint", + plugin: "bun", + use_wasm: true, + working_directory: "src/server", + }, + { + commands: "run test", + enabled: true, + env: { + CI: "true", + NODE_ENV: "test", + }, + logo: "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github/assets/bun.svg", + name: "Client Unit Tests", + plugin: "bun", + use_wasm: true, + working_directory: "src/client", + }, + { + commands: "run test", + enabled: true, + env: { + CI: "true", + NODE_ENV: "test", + }, + logo: "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github/assets/bun.svg", + name: "Server Unit Tests", + plugin: "bun", + use_wasm: true, + working_directory: "src/server", + }, + { + commands: + 'bash "cd src/client && fluentci run --wasm cypress install && cd ../.. && fluentci run --wasm . e2e"', + enabled: true, + name: "End to End Tests", + plugin: "shell", + use_wasm: true, + }, + { + commands: + 'bash "fluentci run --wasm postgres start"\n' + + "bash \"pkgx psql ---host=localhost -d postgres -U `whoami` -c 'CREATE DATABASE test;'\"\n" + + 'bash "fluentci run --wasm . server_e2e"', + enabled: true, + name: "End to End Tests (Server)", + plugin: "shell", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - kotlin.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/kotlin.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + commands: "test", + enabled: true, + name: "test", + plugin: "gradle", + use_wasm: true, + logo: "https://avatars.githubusercontent.com/u/124156", + }, + { + commands: "build", + enabled: true, + name: "build", + plugin: "gradle", + use_wasm: true, + logo: "https://avatars.githubusercontent.com/u/124156", + }, + ]); +}); + +Deno.test("config - php-laravel.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/php-laravel.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + commands: "start", + enabled: true, + env: { + MARIADB_DATABASE: "laravel", + MARIADB_PASSWORD: "password", + MARIADB_USER: "user", + }, + logo: "https://avatars.githubusercontent.com/u/4739304", + name: "Start MariaDB", + plugin: "mariadb", + use_wasm: true, + }, + { + commands: "test", + enabled: true, + env: { + MARIADB_DATABASE: "laravel", + MARIADB_PASSWORD: "password", + MARIADB_USER: "user", + }, + logo: "https://avatars.githubusercontent.com/u/958072", + name: "Run tests", + plugin: "laravel", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - php.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/php.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + commands: + 'bash "fluentci run --wasm php composer_install --no-interaction"\n' + + 'bash "fluentci run --wasm php test"', + enabled: true, + name: "Run tests", + plugin: "shell", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - playwright.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/playwright.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + commands: "install", + enabled: true, + logo: "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github/assets/bun.svg", + name: "Install dependencies", + plugin: "bun", + use_wasm: true, + }, + { + commands: + 'bash "fluentci run --wasm playwright install --with-deps"\n' + + 'bash "fluentci run --wasm playwright test -j $(nproc)"', + enabled: true, + env: { + CI: "true", + }, + name: "Run playwright tests", + plugin: "shell", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - python-django.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/python-django.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + commands: "start", + enabled: true, + env: { + MARIADB_DATABSE: "todo", + MARIADB_PASSWORD: "testrootpass", + MARIADB_USER: "user", + }, + logo: "https://avatars.githubusercontent.com/u/4739304", + name: "Start MariaDB", + plugin: "mariadb", + use_wasm: true, + }, + { + commands: "test", + enabled: true, + env: { + MARIADB_DATABSE: "todo", + MARIADB_HOST: "127.0.0.1", + MARIADB_PASSWORD: "testrootpass", + MARIADB_ROOT_PASSWORD: "root", + MARIADB_USER: "user", + }, + logo: "https://avatars.githubusercontent.com/u/27804", + name: "Run tests", + plugin: "django", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - python-flask.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/python-flask.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + commands: "start", + enabled: true, + logo: "https://avatars.githubusercontent.com/u/45120", + name: "Start MongoDB", + plugin: "mongo", + use_wasm: true, + }, + { + commands: + 'bash "fluentci run --wasm devbox run pip install -r requirements.txt"\n' + + 'bash "fluentci run --wasm devbox run python run.py &"\n' + + 'bash "sleep 2"\n' + + 'bash "fluentci run --wasm devbox run python -m unittest"', + enabled: true, + env: { + DB: "mongodb://localhost:27017/tasks", + PORT: "5000", + }, + name: "Run tests", + plugin: "shell", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - react-native.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/react-native.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + commands: "install", + enabled: true, + logo: "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github/assets/bun.svg", + name: "Install dependencies", + plugin: "bun", + use_wasm: true, + }, + { + commands: "assemble_release", + enabled: true, + logo: "https://upload.wikimedia.org/wikipedia/commons/3/31/Android_robot_head.svg", + name: "Run gradle assemble", + plugin: "android", + use_wasm: true, + working_directory: "android", + }, + ]); +}); + +Deno.test("config - ruby-on-rails.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/ruby-on-rails.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + commands: "start", + enabled: true, + env: { + POSTGRES_DB: "demo_rails_test", + POSTGRES_USER: "postgres", + }, + logo: "https://upload.wikimedia.org/wikipedia/commons/2/29/Postgresql_elephant.svg", + name: "Start Postgres", + plugin: "postgres", + use_wasm: true, + }, + { + commands: "bundle_exec rubocop", + enabled: true, + env: { + RUBY_VERSION: "3.1.4", + }, + logo: "https://avatars.githubusercontent.com/u/210414", + name: "Check style + security", + plugin: "ruby", + use_wasm: true, + }, + { + commands: + 'bash "fluentci run --wasm ruby bundle_exec rails db:migrate"\n' + + 'bash "fluentci run --wasm ruby bundle_exec rails db:seed"\n' + + 'bash "fluentci run --wasm ruby bundle_exec rails test"\n' + + 'bash "fluentci run --wasm ruby bundle_exec rails spec"', + enabled: true, + env: { + RAILS_ENV: "test", + }, + name: "Run tests", + plugin: "shell", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - ruby.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/ruby.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + commands: "bundle_exec rspec", + enabled: true, + logo: "https://avatars.githubusercontent.com/u/210414", + name: "Run tests", + plugin: "ruby", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - rust.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/rust.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + commands: "setup", + enabled: true, + logo: "https://avatars.githubusercontent.com/u/5430905", + name: "Setup Rust", + plugin: "rust", + use_wasm: true, + }, + { + commands: + 'bash "fluentci run --wasm postgres start"\n' + + "bash \"curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash\"\n" + + 'bash "cargo-binstall sqlx-cli -y"\n' + + 'bash "sqlx migrate run"\n' + + 'bash "cargo sqlx prepare"\n' + + 'bash "cargo test"', + enabled: true, + env: { + DATABASE_URL: "postgres://postgres@localhost/demo", + POSTGRES_DB: "demo", + POSTGRES_USER: "postgres", + }, + name: "Run tests", + plugin: "shell", + use_wasm: true, + }, + { + commands: "build", + enabled: true, + env: { + DATABASE_URL: "postgres://postgres@localhost/demo", + }, + logo: "https://avatars.githubusercontent.com/u/5430905", + name: "Run build", + plugin: "rust", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - swift.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/swift.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + commands: "test", + enabled: true, + logo: "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github/assets/swift.svg", + name: "Run tests", + plugin: "swift", + use_wasm: true, + }, + { + commands: "build", + enabled: true, + logo: "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github/assets/swift.svg", + name: "Build", + plugin: "swift", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - symfony.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/symfony.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + commands: + 'bash "fluentci run --wasm symfony container_lint"\n' + + 'bash "fluentci run --wasm symfony doctrine_lint"\n' + + 'bash "fluentci run --wasm symfony phpstan"\n' + + 'bash "fluentci run --wasm symfony phpunit"\n' + + 'bash "fluentci run --wasm symfony twig_lint"\n' + + 'bash "fluentci run --wasm symfony xliff_lint"\n' + + 'bash "fluentci run --wasm symfony yaml_lint"', + enabled: true, + name: "Run lint checks and tests", + plugin: "shell", + use_wasm: true, + }, + ]); +}); + +Deno.test("config - zig.fluentci.toml", () => { + const data = Deno.readFileSync("fixtures/zig.fluentci.toml"); + const config = parseConfig(new TextDecoder().decode(data)); + assertEquals(config, [ + { + commands: "test", + enabled: true, + logo: "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github/assets/zig-original.svg", + name: "test", + plugin: "zig", + use_wasm: true, + }, + { + commands: "build", + enabled: true, + logo: "https://cdn.jsdelivr.net/gh/fluent-ci-templates/.github/assets/zig-original.svg", + name: "build", + plugin: "zig", + use_wasm: true, + }, + ]); +}); diff --git a/src/parser/config.ts b/src/parser/config.ts new file mode 100644 index 0000000..ddc1674 --- /dev/null +++ b/src/parser/config.ts @@ -0,0 +1,101 @@ +import { toml, _ } from "../../deps.ts"; +import logos from "../logos.ts"; +import { Actions, ActionsSchema, ConfigSchema } from "../types.ts"; + +export function parseConfig(content: string): Actions { + const data = ConfigSchema.parse(toml.parse(content)); + + const actions = ActionsSchema.parse( + data.steps?.map((step) => { + const action: Record = { + name: step.name, + use_wasm: true, + enabled: true, + }; + + if (step.env) { + step.env + .filter((env) => env.split("=").length === 2) + .forEach((env) => { + const [key, value] = env.split("="); + _.set(action, ["env", key], value); + }); + } + + if (step.working_directory) { + action.working_directory = step.working_directory; + } + + if ( + Array.isArray(step.command) && + step.command.length === 1 && + step.command[0].startsWith("fluentci") + ) { + const plugin = step.command[0] + .replaceAll("fluentci run", "") + .replaceAll("--wasm", "") + .trim() + .split(" ")[0]; + const commands = step.command[0] + .replaceAll("fluentci run", "") + .replaceAll("--wasm", "") + .trim() + .split(" ") + .slice(1) + .join(" "); + + if (logos[plugin]) { + action.logo = logos[plugin]; + } + + return { + ...action, + commands, + plugin, + }; + } + + if ( + typeof step.command === "string" && + step.command.startsWith("fluentci") + ) { + const plugin = step.command + .replaceAll("fluentci run", "") + .replaceAll("--wasm", "") + .trim() + .split(" ")[0]; + const commands = step.command + .replaceAll("fluentci run", "") + .replaceAll("--wasm", "") + .trim() + .split(" ") + .slice(1) + .join(" "); + + if (logos[plugin]) { + action.logo = logos[plugin]; + } + + return { + ...action, + commands, + plugin, + }; + } + + return { + ...action, + commands: + "bash " + + (Array.isArray(step.command) + ? (step.command as string[]) + .map((command) => `"${command}"`) + .join("\nbash ") + : `"${step.command}"`), + plugin: "shell", + }; + }) + ); + + return actions; +} diff --git a/src/server/executor.ts b/src/server/executor.ts index ca7627c..1e99b7b 100644 --- a/src/server/executor.ts +++ b/src/server/executor.ts @@ -31,6 +31,7 @@ export default async function run(ctx: Context, actions: Action[], data: Run) { date: new Date().toISOString(), }); let run = await ctx.kv.runs.get(data.id); + ctx.runs.set(data.id, run!); for (const action of actions) { if (!action.enabled) { @@ -72,12 +73,43 @@ export default async function run(ctx: Context, actions: Action[], data: Run) { `fluentci run ${action.useWasm ? "--wasm" : ""} ${ action.plugin } ${cmd}`, - project?.path, - jobs[currentActionIndex].id + action.workingDirectory + ? project + ? `${project?.path}/${action.workingDirectory}` + : undefined + : project?.path, + jobs[currentActionIndex].id, + data.id, + action.env + ? Object.fromEntries(action.env.map((x) => x.split("="))) + : undefined ); logs.push(...result.logs); + if (result.cancelled) { + jobs = jobs.map((job, j) => ({ + ...job, + status: currentActionIndex === j ? "CANCELLED" : job.status, + duration: + currentActionIndex === j + ? dayjs().diff(start, "milliseconds") + : job.duration, + logs: + currentActionIndex === j + ? [...(job.logs || []), ...result.logs] + : job.logs, + })); + + await ctx.kv.runs.save(data.projectId, { + ...run!, + jobs, + status: "CANCELLED", + }); + + return; + } + if (result.code !== 0) { Object.values(ctx.sockets).forEach((s) => sendSocketMessage( @@ -119,6 +151,8 @@ export default async function run(ctx: Context, actions: Action[], data: Run) { await stopServices(project?.path!); } + ctx.runs.delete(data.id); + return; } } @@ -168,20 +202,26 @@ export default async function run(ctx: Context, actions: Action[], data: Run) { if (actions.some((x) => x.useWasm)) { await stopServices(project?.path!); } + + ctx.runs.delete(data.id); } async function spawn( ctx: Context, cmd: string, cwd = Deno.cwd(), - jobId?: string + jobId: string, + runId: string, + env?: Record ) { + const cancelled = ctx.runs.get(runId) ? false : true; const logs: Log[] = []; const child = new Deno.Command("bash", { args: ["-c", cmd], stdout: "piped", stderr: "piped", cwd, + env, }).spawn(); const writableStdoutStream = new WritableStream({ @@ -230,5 +270,5 @@ async function spawn( child.status, ]); - return { logs, code }; + return { logs, code, cancelled }; } diff --git a/src/server/graphql/context.ts b/src/server/graphql/context.ts index c16aafe..c30f254 100644 --- a/src/server/graphql/context.ts +++ b/src/server/graphql/context.ts @@ -1,4 +1,5 @@ import { Pagination } from "../kv.ts"; +import { ExecutionEvent } from "./event.ts"; import { Action } from "./objects/action.ts"; import { Project } from "./objects/project.ts"; import { Run } from "./objects/run.ts"; @@ -35,4 +36,5 @@ export type KV = { export type Context = { sockets: Record; kv: KV; + runs: Map; }; diff --git a/src/server/graphql/event.ts b/src/server/graphql/event.ts new file mode 100644 index 0000000..b369486 --- /dev/null +++ b/src/server/graphql/event.ts @@ -0,0 +1,3 @@ +import { EventEmitter } from "node:events"; + +export class ExecutionEvent extends EventEmitter {} diff --git a/src/server/graphql/objects/action.ts b/src/server/graphql/objects/action.ts index e4e7e43..16953a2 100644 --- a/src/server/graphql/objects/action.ts +++ b/src/server/graphql/objects/action.ts @@ -7,6 +7,8 @@ export class Action { useWasm: boolean; logo?: string | null; githubUrl?: string | null; + env?: string[] | null; + workingDirectory?: string | null; constructor({ id, @@ -17,6 +19,8 @@ export class Action { useWasm, logo, githubUrl, + env, + workingDirectory, }: Action) { this.id = id; this.name = name; @@ -26,5 +30,7 @@ export class Action { this.useWasm = useWasm; this.logo = logo; this.githubUrl = githubUrl; + this.env = env; + this.workingDirectory = workingDirectory; } } diff --git a/src/server/graphql/objects/project.ts b/src/server/graphql/objects/project.ts index e430f0d..e1c437c 100644 --- a/src/server/graphql/objects/project.ts +++ b/src/server/graphql/objects/project.ts @@ -20,6 +20,7 @@ export class Project { isPrivate?: boolean; owner?: string; archived?: boolean; + repositoryUrl?: string; constructor({ id, @@ -40,6 +41,7 @@ export class Project { isPrivate, owner, archived, + repositoryUrl, }: Project) { this.id = id; this.path = path; @@ -59,5 +61,6 @@ export class Project { this.isPrivate = isPrivate; this.owner = owner; this.archived = archived; + this.repositoryUrl = repositoryUrl; } } diff --git a/src/server/graphql/resolvers/project/mutations.ts b/src/server/graphql/resolvers/project/mutations.ts index 891f3c7..5058b65 100644 --- a/src/server/graphql/resolvers/project/mutations.ts +++ b/src/server/graphql/resolvers/project/mutations.ts @@ -1,5 +1,10 @@ // deno-lint-ignore-file no-unused-vars no-explicit-any import { createId, dockernames, _ } from "../../../../../deps.ts"; +import { cloneRepository } from "../../../../git.ts"; +import { parseConfig } from "../../../../parser/config.ts"; +import run from "../../../../shared/run.ts"; +import { Actions } from "../../../../types.ts"; +import { directoryExists, fileExists } from "../../../../utils.ts"; import icons from "../../../icons.ts"; import { Context } from "../../context.ts"; import { Project } from "../../objects/project.ts"; @@ -13,12 +18,6 @@ export async function createProject( let name = dockernames.getRandomName().replaceAll("_", "-"); let suffix = 1; - const project = await ctx.kv.projects.at("empty"); - - if (project) { - return project; - } - do { const project = await ctx.kv.projects.byName(name); if (!project) { @@ -28,17 +27,124 @@ export async function createProject( suffix++; } while (true); + const project = await ctx.kv.projects.at("empty"); const icon = _.sample(icons); + let actions: Actions = []; + + if (args.fromRepository) { + const cacheDir = `${Deno.env.get( + "HOME" + )}/.fluentci/cache/${args.fromRepository + .replace("https://", "") + .replace("http://", "") + .replace(".git", "") + .split("/") + .slice(0, -1) + .join("/")}`; + await Deno.mkdir(cacheDir, { recursive: true }); + const repoPath = `${cacheDir}/${args.fromRepository + .split("/") + .pop() + .replace(".git", "")}`; + if (!(await directoryExists(repoPath))) { + await cloneRepository(args.fromRepository, cacheDir); + } + + if (await fileExists(`${repoPath}/.fluentci/fluentci.toml`)) { + const content = await Deno.readTextFile( + `${repoPath}/.fluentci/fluentci.toml` + ); + actions = parseConfig(content); + } + + await new Deno.Command("cp", { + args: [ + "-r", + repoPath, + `${Deno.env.get("HOME")}/.fluentci/workspace/${ + project ? project.name : name + }`, + ], + }).spawn().status; + } + + if (project) { + if (args.fromRepository) { + await ctx.kv.projects.save({ + ...project, + path: `${Deno.env.get("HOME")}/.fluentci/workspace/${project.name}`, + }); + await ctx.kv.projects.remove(project.path); + + await ctx.kv.actions.save( + project.id, + actions.map((action) => ({ + commands: action.commands, + enabled: action.enabled, + githubUrl: action.github_url, + logo: action.logo, + name: action.name, + plugin: action.plugin, + useWasm: action.use_wasm, + env: action.env + ? Object.entries(action.env).map( + ([key, value]) => `${key}=${value}` + ) + : [], + workingDirectory: action.working_directory, + })) + ); + + run( + ctx, + { + ...project, + path: `${Deno.env.get("HOME")}/.fluentci/workspace/${project.name}`, + }, + true + ); + } + return project; + } + + if (args.fromRepository) { + await ctx.kv.actions.save( + projectId, + actions.map((action) => ({ + commands: action.commands, + enabled: action.enabled, + githubUrl: action.github_url, + logo: action.logo, + name: action.name, + plugin: action.plugin, + useWasm: action.use_wasm, + env: action.env + ? Object.entries(action.env).map(([key, value]) => `${key}=${value}`) + : [], + workingDirectory: action.working_directory, + })) + ); + } + await ctx.kv.projects.save({ id: projectId, - path: "empty", + path: args.fromRepository + ? `${Deno.env.get("HOME")}/.fluentci/workspace/${name}` + : "empty", name, createdAt: new Date().toISOString(), picture: `https://img.icons8.com/color-glass/96/${icon}.png`, }); + + if (args.fromRepository) { + run(ctx, (await ctx.kv.projects.get(projectId))!, true); + } + return new Project({ id: projectId, - path: Deno.cwd(), + path: args.fromRepository + ? `${Deno.env.get("HOME")}/.fluentci/workspace/${name}` + : Deno.cwd(), name, createdAt: new Date().toISOString(), picture: `https://img.icons8.com/color-glass/96/${icon}.png`, diff --git a/src/server/graphql/resolvers/run/mutations.ts b/src/server/graphql/resolvers/run/mutations.ts index efda8e5..97f2aa0 100644 --- a/src/server/graphql/resolvers/run/mutations.ts +++ b/src/server/graphql/resolvers/run/mutations.ts @@ -15,3 +15,16 @@ export async function runPipeline( } return run(ctx, project, args.wait); } + +export async function cancelRun( + _root: any, + args: any, + ctx: Context +): Promise { + const run = await ctx.kv.runs.get(args.id); + if (!run) { + throw new GraphQLError(`no run found with id ${args.id}`); + } + ctx.runs.delete(args.id); + return run; +} diff --git a/src/server/graphql/schema.ts b/src/server/graphql/schema.ts index 9131324..6414970 100644 --- a/src/server/graphql/schema.ts +++ b/src/server/graphql/schema.ts @@ -17,7 +17,7 @@ import { unarchiveProject, updateProject, } from "./resolvers/project/mutations.ts"; -import { runPipeline } from "./resolvers/run/mutations.ts"; +import { cancelRun, runPipeline } from "./resolvers/run/mutations.ts"; import { countRuns, getRun, getRuns } from "./resolvers/run/queries.ts"; import { Run } from "./objects/run.ts"; import { Action } from "./objects/action.ts"; @@ -85,6 +85,7 @@ builder.objectType(Project, { isPrivate: t.exposeBoolean("isPrivate", { nullable: true }), owner: t.exposeString("owner", { nullable: true }), archived: t.exposeBoolean("archived", { nullable: true }), + repositoryUrl: t.exposeString("repositoryUrl", { nullable: true }), }), }); @@ -124,6 +125,8 @@ builder.objectType(Action, { useWasm: t.exposeBoolean("useWasm"), logo: t.exposeString("logo", { nullable: true }), githubUrl: t.exposeString("githubUrl", { nullable: true }), + env: t.exposeStringList("env", { nullable: true }), + workingDirectory: t.exposeString("workingDirectory", { nullable: true }), }), }); @@ -136,6 +139,8 @@ export const ActionInput = builder.inputType("ActionInput", { useWasm: t.boolean({ required: true }), logo: t.string({ required: false }), githubUrl: t.string({ required: false }), + env: t.stringList({ required: false }), + workingDirectory: t.string({ required: false }), }), }); @@ -249,6 +254,9 @@ builder.mutationType({ createProject: t.field({ type: Project, resolve: createProject, + args: { + fromRepository: t.arg.string({ required: false }), + }, }), updateProject: t.field({ type: Project, @@ -269,6 +277,13 @@ builder.mutationType({ }, resolve: runPipeline, }), + cancelRun: t.field({ + type: Run, + args: { + id: t.arg.id(), + }, + resolve: cancelRun, + }), runJob: t.field({ type: Job, args: { diff --git a/src/server/icons.ts b/src/server/icons.ts index efeab8a..c566368 100644 --- a/src/server/icons.ts +++ b/src/server/icons.ts @@ -168,7 +168,6 @@ export default [ "solar-panel", "wind-turbine", "automatic", - "automation", "bot", "engineering", "microscope", @@ -183,7 +182,6 @@ export default [ "aircraft", "airport", "helicopter", - "plane", "rocket", "bicycle", "motorbike-helmet", @@ -262,7 +260,6 @@ export default [ "evergreen", "field", "flower", - "flower-bouquet", "lotus", "mushroom", "olive", diff --git a/src/server/kv/projects.ts b/src/server/kv/projects.ts index bf49b6c..a43d272 100644 --- a/src/server/kv/projects.ts +++ b/src/server/kv/projects.ts @@ -133,6 +133,9 @@ export async function count() { } export async function remove(id: string) { + if (await kv.get([FLUENTCI_KV_PREFIX, "path", id])) { + await kv.delete([FLUENTCI_KV_PREFIX, "path", id]); + } const project = await get(id); if (!project) return; await kv diff --git a/src/types.ts b/src/types.ts index 787e69c..9e93cb7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,4 @@ -import { z } from "https://deno.land/x/zod@v3.22.2/mod.ts"; +import { z } from "../deps.ts"; export const LabelSchema = z.object({ name: z.string(), @@ -52,8 +52,12 @@ export const ActionSchema = z.object({ use_wasm: z.boolean(), logo: z.string().optional().nullable(), github_url: z.string().optional().nullable(), + env: z.record(z.string()).optional().nullable(), + working_directory: z.string().optional().nullable(), }); +export const ActionsSchema = z.array(ActionSchema); + export const LogSchema = z.object({ id: z.string(), jobId: z.string(), @@ -90,6 +94,28 @@ export const RunSchema = z.object({ status: z.string().optional().nullable(), }); +export const ConfigSchema = z.object({ + steps: z + .array( + z.object({ + command: z.union([z.string(), z.array(z.string())]), + name: z.string(), + env: z.array(z.string()).optional(), + working_directory: z.string().optional(), + }) + ) + .optional(), + package: z + .object({ + name: z.string(), + version: z.string(), + description: z.string().optional(), + license: z.string().optional(), + authors: z.array(z.string()).optional(), + }) + .optional(), +}); + export type Pipeline = z.infer; export type Label = z.infer; @@ -100,8 +126,12 @@ export type Agent = z.infer; export type Action = z.infer; +export type Actions = z.infer; + export type Log = z.infer; export type Run = z.infer; export type Job = z.infer; + +export type Config = z.infer; diff --git a/src/utils.ts b/src/utils.ts index 5ef1ffd..943be6a 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -364,8 +364,17 @@ export async function fluentciPluginDirExists(cwd = "."): Promise { export async function directoryExists(path: string): Promise { try { - const fluentciDir = await Deno.stat(path); - return fluentciDir.isDirectory; + const dir = await Deno.stat(path); + return dir.isDirectory; + } catch (_) { + return false; + } +} + +export async function fileExists(path: string): Promise { + try { + const file = await Deno.stat(path); + return file.isFile; } catch (_) { return false; } diff --git a/tests/consts.test.ts b/tests/consts.test.ts index c6133f4..44be64b 100644 --- a/tests/consts.test.ts +++ b/tests/consts.test.ts @@ -1,4 +1,4 @@ -import { assertEquals } from "https://deno.land/std@0.206.0/assert/mod.ts"; +import { assertEquals } from "../deps.ts"; import { FLUENTCI_API_URL, FLUENTCI_WS_URL } from "../src/consts.ts"; Deno.test("FLUENTCI_API_URL", () => { diff --git a/tests/types.test.ts b/tests/types.test.ts index e15102c..6c33e7f 100644 --- a/tests/types.test.ts +++ b/tests/types.test.ts @@ -6,7 +6,7 @@ import { LogEventSchema, Label, } from "../src/types.ts"; -import { assertEquals } from "https://deno.land/std@0.206.0/assert/mod.ts"; +import { assertEquals } from "../deps.ts"; Deno.test("LabelSchema", () => { const label: Label = {