{"id":13801731,"url":"https://github.com/denoflow/denoflow","last_synced_at":"2025-04-09T20:15:31.365Z","repository":{"id":37468823,"uuid":"444281513","full_name":"denoflow/denoflow","owner":"denoflow","description":"Configuration as Code, use YAML to write automated workflows that run on Deno, with any Deno modules, Typescript/Javascript codes","archived":false,"fork":false,"pushed_at":"2023-10-04T17:12:38.000Z","size":170,"stargazers_count":282,"open_issues_count":0,"forks_count":6,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-09T20:15:28.624Z","etag":null,"topics":["actions","ansible","automated","comtrya","deno","ifttt","typescript","workflow","zapier"],"latest_commit_sha":null,"homepage":"https://playground.owenyoung.com/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/denoflow.png","metadata":{"files":{"readme":"README-ZH.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-04T04:09:40.000Z","updated_at":"2025-03-23T18:24:50.000Z","dependencies_parsed_at":"2024-08-04T00:17:54.912Z","dependency_job_id":null,"html_url":"https://github.com/denoflow/denoflow","commit_stats":{"total_commits":93,"total_committers":2,"mean_commits":46.5,"dds":"0.16129032258064513","last_synced_commit":"a92638a5a7f615c7801677de82f0cb387b322187"},"previous_names":[],"tags_count":35,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/denoflow%2Fdenoflow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/denoflow%2Fdenoflow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/denoflow%2Fdenoflow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/denoflow%2Fdenoflow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/denoflow","download_url":"https://codeload.github.com/denoflow/denoflow/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248103872,"owners_count":21048245,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["actions","ansible","automated","comtrya","deno","ifttt","typescript","workflow","zapier"],"created_at":"2024-08-04T00:01:26.534Z","updated_at":"2025-04-09T20:15:31.342Z","avatar_url":"https://github.com/denoflow.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","Tools"],"sub_categories":["XML"],"readme":"# Denoflow\n\n[![Discord](https://img.shields.io/discord/932645476413628446?color=7289DA\u0026label=Join%20Community)](https://discord.gg/wz6UJpGqtb)\n\n[Deno Land](https://deno.land/x/denoflow)\n\n## Table of Contents\n\n- [关于](#about)\n- [快速开始](#getting_started)\n- [如何使用](#usage)\n- [常见问题](#faq)\n\n## About \u003ca name = \"about\"\u003e\u003c/a\u003e\n\n使用denoflow，你将可以使用人体工学设计的yaml配置文件来编写自动化工作流程，简单而强大，在Deno上运行，可以使用任何Deno模块、Typescript/Javascript代码。Denoflow会按照你的要求执行你的工作流。可以把它看作是某种配置即代码工具。\n\n\u003e 项目仍处于非常早期的阶段，谨慎使用!\n\n理想的结果是拥有一些UI界面，使用[rjsf](https://github.com/rjsf-team/react-jsonschema-form)等json schema语言来渲染界面的工具生成一个web gui，gui可以帮助我们生成yaml配置。\n\n理想的运行环境是使用云无服务器平台，或CI平台，如[Github Actions](https://github.com/features/actions)，[Gitlab CI](https://gitlab.com/gitlab-org/gitlab-ci-runner/)，使用[Deno](https://deno.land/)自我托管，或任何Docker运行时。\n\n\u003e [Deno Deploy](https://deno.com/deploy) 目前还不支持，因为Deno Deploy不支持运行字符串生成的代码。\n\n\u003e 查看Github Actions的作为运行时的例子： [test.yml](./.github/workflows/test.yml)\n\n\u003e 加入[Discord](https://discord.gg/wz6UJpGqtb)聊天频道，讨论Denoflow!\n\n\u003e 稳定的Deno Land的版本见[Denoflow](https://deno.land/x/denoflow)\n\n## 能做什么？\n\n- 比如做一个Github Webhook来在服务器同步部署最新代码\n- 比如监听RSS的更新，发送到Telegram或者Discord等\n- 以及其他一切可以通过API互相调用的流程\n\n## 在线体验\n\n现在可以通过[Online Playground](https://playground.owenyoung.com)来在线尝试和探索 Denoflow\n\n## 为什么是Deno?\n\n- Deno使用URL来导入模块，给了我们非常灵活和方便的工作流脚本功能，让我门可以非常容易地使用任何想要的模块。\n- Deno基于JavaScript语言的现代特性，官方提供了一个标准库，涵盖了工作流中的大部分常用功能。\n- Deno默认的零权限设计，这对工作流的安全性很重要，这样你就可以只给你的工作流提供它们需要的权限。\n\n\u003e 我之前写过[actionsflow](https://actionsflow.github.io/)，必须在github actions中运行，或者本地启用Docker运行，实际上经验来说，这对于大多数人想要的轻量级工作流来说太重了，我发现Deno的特性使得它非常适合做基于yaml配置的灵活工作流。所以，Denoflow的设计特别轻量，甚至没有常驻的功能，必须由外部的东西去运行它，比如github actions的trigger，或者无服务器的定时触发，http触发等。\n\n## 先决条件\n\n先安装[Deno](https://deno.land/#installation)\n\n## Getting Started \u003ca name = \"getting_started\"\u003e\u003c/a\u003e\n\n从Hacker News的API获取数据，发送到某个webhook的示例：\n\n```bash\nmkdir workflows\n```\n\n```bash\ntouch workflows/fetch.yml\n```\n\n```yaml\nsources:\n  - from: https://deno.land/x/axiod@0.24/mod.ts\n    use: get\n    args:\n      - https://test.owenyoung.com/slim.json\n    itemsPath: data.hits\n    key: objectID\n    limit: 1\nsteps: \n  - run: console.log('item', ctx.item)\n  # Open: \u003chttps://requestbin.com/r/enyvb91j5zjv9/23eNPamD4DK4YK1rfEB1FAQOKIj\u003e , See live webhook request.\n  - from: https://deno.land/x/axiod@0.24/mod.ts\n    use: post\n    args:\n      - https://enyvb91j5zjv9.x.pipedream.net/\n      -  ${{ctx.item}}\n      - headers:\n          'Content-Type': 'application/json'\n```\n\n打开: \u003chttps://requestbin.com/r/enyvb91j5zjv9/23eNPamD4DK4YK1rfEB1FAQOKIj\u003e , 查看实时的webhook请求\n\n```bash\ndeno run --allow-read --allow-net --allow-write --allow-env --allow-run https://deno.land/x/denoflow/cli.ts run\n```\n\n\u003e 或者简单点，直接给予所有权限（不建议生产环境这样做）：`deno run -A https://deno.land/x/denoflow/cli.ts run`\n\n\u003e Denoflow默认将扫描`workflows`目录并运行所有有效的`.yml`文件。\n\n\u003e Denoflow的仓库最新版本：`https://denopkg.com/denoflow/denoflow@main/cli.ts`。\n\n\u003e 你也可以[在线体验该示例](https://playground.owenyoung.com/)\n\n如果你更喜欢用`fetch`：\n\n```yaml\nsources:\n  - use: fetch\n    args:\n      - https://test.owenyoung.com/slim.json\n    run: return ctx.result.json()\n    itemsPath: hits\n    key: objectID\n    limit: 1\nsteps: \n  - use: fetch\n    args:\n      - https://enyvb91j5zjv9.x.pipedream.net/\n      - method: POST\n        headers:\n          Content-Type: application/json\n        body: ${{JSON.stringify(ctx.item)}}\n\n```\n\n\u003e 在 [Online Playground](https://playground.owenyoung.com/#code=M4ewrgTgxgpsBcAoABMgtMswb2QMxgBcoALFVZAQwgHMFyL1kTDCAHBAek8LkIDoQAdxgA7AJ7hRNflBABbTsAA2AS3n8AVqFENkEMKNwQikUciiEAHvxPAwygdpCiAFAEo9q3vOAAFSkISXBJvYD0AaxhxXBAAI00YSwBJABE9NXlvXABGRGBeDlxyDAMjCxdQZRh+ZRAaVwBybxh5RoAaSxsWjUJvavcAbnIAYmQAeTYxXAAeFnYuThMARzA+ONVRWQUlzjFxADc4gE4czQBWAC9NA+POACYAZhgAOQD5VIAWVIBpT4BNH45CB4ACiACEcgAxACCAEVxj9kpoAHzIdrIADKMBgyDUB1xIjiJBAIAi+hgqz4-BKmGwuAIxDIjGodCQjFQGHmRW4+yOpwu11u-BsbFUUwAJiZKBpREROHpOch5EQSRLcH5xpiACqKigkGCUCUwCD0DkcxoAYRcvFEhDQ2vEU0auEalDYbDUUECqhcnGcokaetQcRAEpiyAAJABvaMAKUx4xe-AKEE2NFUeHEri6-B67gAvgXEEA) 体验该实例\n\n## RSS Feed to Discord Webhook Message\n\n发送RSS源最新文章到Discord频道消息的示例：\n\n```bash\ntouch workflows/rss.yml\n```\n\n\n```yaml\nsources:\n  - from: https://deno.land/x/denoflow@0.0.19/sources/rss.ts\n    args:\n      - https://actionsflow.github.io/test-page/hn-rss.xml\n    limit: 1\nsteps:\n  - use: fetch\n    args:\n      - ${{env.DISCORD_WEBHOOK}}\n      - method: POST\n        headers:\n          Content-Type: application/json\n        body: ${{ JSON.stringify({content:ctx.item.title.value}) }}\n```\n\n\u003e 在[Online Playground](https://playground.owenyoung.com/#code=M4ewrgTgxgpsBcAoABMgtMgZhEBbeyAFgC7EAOCA9JQCYwB2IAdADYCG9NlAHrQyJhYgA7gAEADE0kAmAIyVQkWMEoRgwJsWApUyNhADmCHbvRFSFeNTZRiASxD1ggkUwN3ihMACMmDysRwxGhkbAYwlIT0aGoa3LgsJsgsdrgeBLJJmCDQMATEEGAwiMCBljoYhfQEUI6gLDCsIAYAFADkHjC4bQA0ttx+gbgAlBXIYMB5WDDEUIRJAMTIAPJkDAQAPCTkVKowAI5Fpd529Ey1uKqUDACeAG7eAJyyAFYArABeL3ePlNIAzDAAHIABTYuAAIgAWCEAaShAE1YbIIJgAKIAIVkADEAIIARWWsIAki8AHzIHrIADKMBgyTsd3pwhg3kIIBAAGtkBADkdiEweTAyOxYMgbuAIMgWWyOdzCDBeUkGHckKZUBDidSAMLLABKEIA+gB1TEACWWRII20s1FuD2e7y+PyYAzIdjWNF54KY9BmlCS+iMavVGAAJABvCP9JgqpianX6o2mjEWokAX3TSVQGFwM3ZNAIIOW1IAKtndAq2HQ1CH1bptY5AvRgqWbmsCGwyCK7FA2PZHJQXqB6BXUN4QDQbgRIxHkAApanLIFMUoQU7uTA3FrRpsMYjwGOdXCaDwNJh3NgsIrp4bITOIIA)上尝试\n\n\n或者，如果你更喜欢原生一点的方法:\n\n```yaml\nsources:\n  - use: fetch\n    args:\n      - https://actionsflow.github.io/test-page/hn-rss.xml\n    run: |\n      const rss = await import(\"https://deno.land/x/rss/mod.ts\");\n      const xml = await ctx.result.text();\n      const feed = await rss.parseFeed(xml);\n      return feed.entries;\n    limit: 1\nsteps:\n  - use: fetch\n    args:\n      - ${{ctx.env.DISCORD_WEBHOOK}}\n      - method: POST\n        headers:\n          'Content-Type': 'application/json'\n        body: ${{ JSON.stringify({content:ctx.item.title.value}) }}\n```\n\n```bash\ndeno run --allow-read --allow-net --allow-write --allow-run --allow-env https://deno.land/x/denoflow/cli.ts run\n```\n\n\u003e 在 [Online Playground](https://playground.owenyoung.com/#code=M4ewrgTgxgpsBcAoABMgtMswb2QMxgBcoALFVZAQwgHMFyL1kTDCAHBAek8qkIEsQAO2B4ANiADuAOhr9CJMACNpgzoTiE0bSjRicSQtBGDBpADwC2YhsghghuAD63UUYcEJ3TyALxVJSnlkfks2EAhCAAoAIhZ2Lk4AExghEGkxSiEkznNOE2BOSxAk6UJgGIBKAG5XZHcRLysxPwCgrz5zaQg4MDFCMphzaJq6hs98GBgk1spA4ILpHRMYADEppKjm0cZUHsJIIUnp6VTCCH44WsYxUPlcAEZETxgOJFQMLBxJ4jJGAGJkAB5NipXAAHnib24PQAjmBNEp+EJpO5LPlOKkAJ4ANyUAE4HgArACsAC8iTj8ZwAEwAZhgADkAAqUSwAEQALOyANKcgCaPIeEDwAFEAEIPVYAQQAikCeQBJIkAPmQABpkABlKbIW44mDISQwJQkEAgADWdhg8M00mtbEysGQWPAECNJrNluYMB6tlSOPeu3Ziq1AGEgQAldkAfQA6hKABJAhW4KGJbF4wmkilUixLfigpI9NnSIRETi2ah0IOMDAAEgA3o3OqchDjpCHw1HYwnxcmFQBfQd1DCWIhmpK4ZlArUAFTqqBIMEoKRMtd2qDDwg0Qi0c6xoNwlDYjv4UEoAmEnCJoCEi+QShKWNwTcbyAAUlqgYzpJ4LkIch4FiUQtjuZzwK28gwJYZTyGIMDSDilBiAig6VMgw5AA)尝试该示例\n\n一个简单的通过脚本生成数据的例子:\n\n```yaml\nsources:\n  - run: return [{id:\"1\"}]\n    force: true\nsteps: \n  - run: console.log(\"item\",ctx.item);\n```\n\n\u003e 在[Online Playground](https://playground.owenyoung.com/#code=M4ewrgTgxgpsBcAoABMgtMiYB29MwBdJtkBtAbwEsATeAIgEY6BfAXRVWQDMRoY8CWGImAEYABwTIOGLLmRQQ2UABsYAOhUgA5gAo6lMQFs6AGigEAHusMwjASgDciIA)尝试该示例\n\n更多的例子在[workflows](./workflows)目录下，你也可以在这里提交你的工作流\n\n### 生命周期 \n\n1. `sources?`：获取数据的地方，`Source[]`，可以是一个或多个来源。每个源都应该返回一个对象数组,比如`[{\"id\":\"1\"}]`，item的key可以通过`key`指定\n    1. `from`? : 从`url`或`file path`里导入ts/js脚本。 \n    1. `use`? : 从上面的`from`中运行`moduleName`，或者如果没有提供`from`的话，比如`fetch`，将会被当作全局函数，`args`数组将被传递给函数作为参数，返回值将被附加到`ctx.result`和`ctx.sources[index].result`，如果`use`是一个Class类，那么`ctx.result`将是该类的实例。 `use`也可以是`Deno.cwd`的东西，用来调用Deno提供的函数。\n    1. `run`? ：运行ts/js代码，你可以在这里处理`use`结果。返回一个可以被字符串化为json的结果。返回值将被附加到`ctx.result`和`ctx.sources[index].result`。\n    1. `itemsPath`? : 结果中对象数组的路径，如`https://test.owenyoung.com/slim.json`中将是`hits`。\n    1. `key`? : 识别对象的唯一key，如`https://test.owenyoung.com/slim.json`中的`objectID`，如果不提供，将使用`id`，denoflow将对id进行去重。\n    1. `reverse?', `boolean', 是否需要反向排序数组\n    1. `filter?`, `string`, 脚本代码，应处理`ctx.item`，并且返回`true`或`false`。\n    1. `cmd`: `string`, 在所有其他任务之后执行一个shell命令，返回值将附加到`ctx.cmdResult`和`ctx.sources[index].cmdResult`。\n    1. `post?`：后置脚本代码，你可以在这里做一些检查、清理的事情，或者改变`ctx.state`。\n1. `filter`? 从所有合并的sources的`items`中过滤，应该处理`ctx.items`，预期返回一个新的`boolean[]`。\n    1. `from`? : 从`url`或`file path`导入ts/js脚本。 \n    1. `use`? : 从上面的`from`中运行`moduleName`，或者如果没有提供`from`的话，比如`fetch`，将会被当作全局函数，`args`数组将被传递给函数作为参数，返回值将被附加到`ctx.result`和`ctx.sources[index].result`，如果`use`是一个Class类，那么`ctx.result`将是该类的实例。 `use`也可以是`Deno.cwd`的东西，用来调用Deno提供的函数。\n    1. `run`？：运行ts/js代码，你可以在这里处理`use`的结果。处理`ctx.items`，预期返回一个新的`boolean[]`，标志哪个项目将被使用。例如，`run: return ctx.items.map(item =\u003e item.title.value.includes('test'))`。\n    1. `cmd`? : `string`，在所有其他任务之后执行一个shell命令，返回值将被附加到`ctx.cmdResult`和`filter.cmdResult`。\n    1. `post?`：后置脚本代码，你可以在这里做一些检查、清理，改变ctx.state的事情。\n1. `steps`? 要运行的步骤，`Step[]`，可以是一个或多个步骤。\n    1. `from`? : 从`url`或`file path`导入脚本。 \n    1. `use`? : 从上面的`from`中运行`moduleName`，或者如果没有提供`from`的话，比如`fetch`，将会被当作全局函数，`args`数组将被传递给函数作为参数，返回值将被附加到`ctx.result`和`ctx.sources[index].result`，如果`use`是一个Class类，那么`ctx.result`将是该类的实例。 `use`也可以是`Deno.cwd`的东西，用来调用Deno提供的函数。\n    1. `run`? : 运行ts/js代码，你可以在这里处理`use`结果。返回一个可以被字符串化为json的结果。该结果将被附加到`ctx.step[index].result`中。\n    1. `cmd`? : 执行shell命令，将在`run`之后运行，结果将被附加到`ctx.step[index].cmdResult`。\n    1. `post?`：后置脚本代码，你可以在这里做一些检查、清理的事情，改变ctx.state\n1. `post`? 最后的后脚本代码，在所有步骤完成后运行，你可以在这里做一些检查、清洁的事情。你可以在这里使用所有`steps`里的的参数。\n\n### Installing\n\n你也可以直接把Denoflow安装到本机：\n\n```bash\ndeno install -n denoflow --allow-read --allow-net --allow-write --allow-run --allow-env  https://deno.land/x/denoflow/cli.ts\n```\n\n然后就可以使用 `denoflow run` , 或者 `denoflow run \u003cfiles\u003e`来运行你的工作流文件。\n\n\n#### Update to latest version\n\n更新到最新版本：\n\n```bash\ndeno cache --reload https://deno.land/x/denoflow/cli.ts\n```\n\n## Usage \u003ca name = \"usage\"\u003e\u003c/a\u003e\n\n命令行参数：\n\n```bash\ndenoflow/0.0.17\n\nUsage:\n  $ denoflow run [...files or url]\n\nOptions:\n  --force Force run workflow files, if true, will ignore to read/save state\n  --debug Debug mode, will print more info\n  --database Database uri, default json://data\n  --limit max items for workflow every runs\n  --sleep sleep time between sources, filter, steps, unit seconds\n  --stdin read yaml file from stdin, e.g. cat test.yml | denoflow run --stdin\n  -h, --help Display this message\n```\n\n\n\n### YAML Syntax\n\nYAML语法：\n\n如果你还不熟悉YAML语法的话，可以花[5分钟](https://www.codeproject.com/Articles/1214409/Learn-YAML-in-five-minutes)熟悉一下：\n\n你可以在任何字段中使用`${{variable}}`来向你的工作流插入变量，我们在所有可以使用脚本的地方都注入了`ctx`全局变量，利用ctx去访问任何需要的数据，比如说：\n\n#### Expressions\n\n```yaml\nsteps:\n  - if: ${{ctx.items.lengh\u003e10}}\n    run: console.log(ctx.item);\n```\n\n所有的`ctx`变量，可以参考[接口配置文件](./core/interface.ts)\n\n#### 状态\n\n你可以简单地使用`ctx.state`来获取或设置状态，例如。\n\n```js\nlet currentState = ctx.state || {};\n\nlet sent = ctx.state.send || [];\n\nif(sent.includes(ctx.item.id)){\n  sent.push（ctx.item.id）。\n}\n\nctx.state = {\n  sent\n};\n\n// denoflow将为你保存状态，接下来你可以读取它\n```\n\n默认配置，state将以`json`格式保存到`data`文件夹。你也可以使用sqlite来存储数据。在工作流配置文件中设置`database: sqlite://data.sqlite`即可\n\n## Faq\n\n### 如何运行一个定时工作流？\n\n因为denoflow是为无服务器设计的，很简单，所以它本身不能运行定时工作流。但是你可以使用`cron`或其他触发器来触发Denoflow的工作流。比如说使用`cron`:\n\n```bash\n*/15 * * * deno run --allow-read --allow-net --allow-write --allow-env --allow-run https://deno.land/x/denoflow/cli.ts run workflows/schedule15.yml\n```\n\n\n### 如何处理webhook事件？\n\n像上面一样，denoflow不能直接处理webhook，你可以把webhook转发给denoflow，比如使用github actions的例子。\n\n`Webhook.yml`:\n\n```yaml\nsources:\n  - run: return [ctx.env.event]\n    force: true\nsteps: \n  - run: console.log(\"item\",ctx.item);\n```\n\n`.github/workflows/webhook.yml`:\n\n```yaml\nname: Webhook\non:\n  repository_dispatch:\n  workflow_dispatch:\njobs:\n  denoflow:\n    runs-on: ubuntu-latest\n    concurrency: denoflow\n    steps:\n      - name: Check out repository code\n        uses: actions/checkout@v2\n      - uses: denoland/setup-deno@v1\n        with:\n          deno-version: v1.x\n      - env:\n          event: ${{toJSON(github.event)}}\n        run: deno run --allow-read --allow-net --allow-write --allow-env --allow-run https://deno.land/x/denoflow/cli.ts run workflows/webhook.yml\n```\n\n\n\u003e Denoflow还处于早期的阶段，如果你有任何建议，非常欢迎issue和pull request。谢谢！\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdenoflow%2Fdenoflow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdenoflow%2Fdenoflow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdenoflow%2Fdenoflow/lists"}