denoflow

Configuration as Code, use YAML to write automated workflows that run on Deno, with any Deno modules, Typescript/Javascript codes

APACHE-2.0 License

Stars
278
Committers
1

Denoflow

Deno Land

Table of Contents

About

使用denoflow,你将可以使用人体工学设计的yaml配置文件来编写自动化工作流程,简单而强大,在Deno上运行,可以使用任何Deno模块、Typescript/Javascript代码。Denoflow会按照你的要求执行你的工作流。可以把它看作是某种配置即代码工具。

项目仍处于非常早期的阶段,谨慎使用!

理想的结果是拥有一些UI界面,使用rjsf等json schema语言来渲染界面的工具生成一个web gui,gui可以帮助我们生成yaml配置。

理想的运行环境是使用云无服务器平台,或CI平台,如Github ActionsGitlab CI,使用Deno自我托管,或任何Docker运行时。

Deno Deploy 目前还不支持,因为Deno Deploy不支持运行字符串生成的代码。

查看Github Actions的作为运行时的例子: test.yml

加入Discord聊天频道,讨论Denoflow!

稳定的Deno Land的版本见Denoflow

能做什么?

  • 比如做一个Github Webhook来在服务器同步部署最新代码
  • 比如监听RSS的更新,发送到Telegram或者Discord等
  • 以及其他一切可以通过API互相调用的流程

在线体验

现在可以通过Online Playground来在线尝试和探索 Denoflow

为什么是Deno?

  • Deno使用URL来导入模块,给了我们非常灵活和方便的工作流脚本功能,让我门可以非常容易地使用任何想要的模块。
  • Deno基于JavaScript语言的现代特性,官方提供了一个标准库,涵盖了工作流中的大部分常用功能。
  • Deno默认的零权限设计,这对工作流的安全性很重要,这样你就可以只给你的工作流提供它们需要的权限。

我之前写过actionsflow,必须在github actions中运行,或者本地启用Docker运行,实际上经验来说,这对于大多数人想要的轻量级工作流来说太重了,我发现Deno的特性使得它非常适合做基于yaml配置的灵活工作流。所以,Denoflow的设计特别轻量,甚至没有常驻的功能,必须由外部的东西去运行它,比如github actions的trigger,或者无服务器的定时触发,http触发等。

先决条件

先安装Deno

Getting Started

从Hacker News的API获取数据,发送到某个webhook的示例:

mkdir workflows
touch workflows/fetch.yml
sources:
  - from: https://deno.land/x/[email protected]/mod.ts
    use: get
    args:
      - https://test.owenyoung.com/slim.json
    itemsPath: data.hits
    key: objectID
    limit: 1
steps: 
  - run: console.log('item', ctx.item)
  # Open: <https://requestbin.com/r/enyvb91j5zjv9/23eNPamD4DK4YK1rfEB1FAQOKIj> , See live webhook request.
  - from: https://deno.land/x/[email protected]/mod.ts
    use: post
    args:
      - https://enyvb91j5zjv9.x.pipedream.net/
      -  ${{ctx.item}}
      - headers:
          'Content-Type': 'application/json'

打开: https://requestbin.com/r/enyvb91j5zjv9/23eNPamD4DK4YK1rfEB1FAQOKIj , 查看实时的webhook请求

deno run --allow-read --allow-net --allow-write --allow-env --allow-run https://deno.land/x/denoflow/cli.ts run

或者简单点,直接给予所有权限(不建议生产环境这样做):deno run -A https://deno.land/x/denoflow/cli.ts run

Denoflow默认将扫描workflows目录并运行所有有效的.yml文件。

Denoflow的仓库最新版本:https://denopkg.com/denoflow/denoflow@main/cli.ts

你也可以在线体验该示例

如果你更喜欢用fetch

sources:
  - use: fetch
    args:
      - https://test.owenyoung.com/slim.json
    run: return ctx.result.json()
    itemsPath: hits
    key: objectID
    limit: 1
steps: 
  - use: fetch
    args:
      - https://enyvb91j5zjv9.x.pipedream.net/
      - method: POST
        headers:
          Content-Type: application/json
        body: ${{JSON.stringify(ctx.item)}}

Online Playground 体验该实例

RSS Feed to Discord Webhook Message

发送RSS源最新文章到Discord频道消息的示例:

touch workflows/rss.yml
sources:
  - from: https://deno.land/x/[email protected]/sources/rss.ts
    args:
      - https://actionsflow.github.io/test-page/hn-rss.xml
    limit: 1
steps:
  - use: fetch
    args:
      - ${{env.DISCORD_WEBHOOK}}
      - method: POST
        headers:
          Content-Type: application/json
        body: ${{ JSON.stringify({content:ctx.item.title.value}) }}

Online Playground上尝试

或者,如果你更喜欢原生一点的方法:

sources:
  - use: fetch
    args:
      - https://actionsflow.github.io/test-page/hn-rss.xml
    run: |
      const rss = await import("https://deno.land/x/rss/mod.ts");
      const xml = await ctx.result.text();
      const feed = await rss.parseFeed(xml);
      return feed.entries;
    limit: 1
steps:
  - use: fetch
    args:
      - ${{ctx.env.DISCORD_WEBHOOK}}
      - method: POST
        headers:
          'Content-Type': 'application/json'
        body: ${{ JSON.stringify({content:ctx.item.title.value}) }}
deno run --allow-read --allow-net --allow-write --allow-run --allow-env https://deno.land/x/denoflow/cli.ts run

Online Playground尝试该示例

一个简单的通过脚本生成数据的例子:

sources:
  - run: return [{id:"1"}]
    force: true
steps: 
  - run: console.log("item",ctx.item);

Online Playground尝试该示例

更多的例子在workflows目录下,你也可以在这里提交你的工作流

生命周期

  1. sources?:获取数据的地方,Source[],可以是一个或多个来源。每个源都应该返回一个对象数组,比如[{"id":"1"}],item的key可以通过key指定
    1. from? : 从urlfile path里导入ts/js脚本。
    2. use? : 从上面的from中运行moduleName,或者如果没有提供from的话,比如fetch,将会被当作全局函数,args数组将被传递给函数作为参数,返回值将被附加到ctx.resultctx.sources[index].result,如果use是一个Class类,那么ctx.result将是该类的实例。 use也可以是Deno.cwd的东西,用来调用Deno提供的函数。
    3. run? :运行ts/js代码,你可以在这里处理use结果。返回一个可以被字符串化为json的结果。返回值将被附加到ctx.resultctx.sources[index].result
    4. itemsPath? : 结果中对象数组的路径,如https://test.owenyoung.com/slim.json中将是hits
    5. key? : 识别对象的唯一key,如https://test.owenyoung.com/slim.json中的objectID,如果不提供,将使用id,denoflow将对id进行去重。
    6. reverse?', boolean', 是否需要反向排序数组
    7. filter?, string, 脚本代码,应处理ctx.item,并且返回truefalse
    8. cmd: string, 在所有其他任务之后执行一个shell命令,返回值将附加到ctx.cmdResultctx.sources[index].cmdResult
    9. post?:后置脚本代码,你可以在这里做一些检查、清理的事情,或者改变ctx.state
  2. filter? 从所有合并的sources的items中过滤,应该处理ctx.items,预期返回一个新的boolean[]
    1. from? : 从urlfile path导入ts/js脚本。
    2. use? : 从上面的from中运行moduleName,或者如果没有提供from的话,比如fetch,将会被当作全局函数,args数组将被传递给函数作为参数,返回值将被附加到ctx.resultctx.sources[index].result,如果use是一个Class类,那么ctx.result将是该类的实例。 use也可以是Deno.cwd的东西,用来调用Deno提供的函数。
    3. run?:运行ts/js代码,你可以在这里处理use的结果。处理ctx.items,预期返回一个新的boolean[],标志哪个项目将被使用。例如,run: return ctx.items.map(item => item.title.value.includes('test'))
    4. cmd? : string,在所有其他任务之后执行一个shell命令,返回值将被附加到ctx.cmdResultfilter.cmdResult
    5. post?:后置脚本代码,你可以在这里做一些检查、清理,改变ctx.state的事情。
  3. steps? 要运行的步骤,Step[],可以是一个或多个步骤。
    1. from? : 从urlfile path导入脚本。
    2. use? : 从上面的from中运行moduleName,或者如果没有提供from的话,比如fetch,将会被当作全局函数,args数组将被传递给函数作为参数,返回值将被附加到ctx.resultctx.sources[index].result,如果use是一个Class类,那么ctx.result将是该类的实例。 use也可以是Deno.cwd的东西,用来调用Deno提供的函数。
    3. run? : 运行ts/js代码,你可以在这里处理use结果。返回一个可以被字符串化为json的结果。该结果将被附加到ctx.step[index].result中。
    4. cmd? : 执行shell命令,将在run之后运行,结果将被附加到ctx.step[index].cmdResult
    5. post?:后置脚本代码,你可以在这里做一些检查、清理的事情,改变ctx.state
  4. post? 最后的后脚本代码,在所有步骤完成后运行,你可以在这里做一些检查、清洁的事情。你可以在这里使用所有steps里的的参数。

Installing

你也可以直接把Denoflow安装到本机:

deno install -n denoflow --allow-read --allow-net --allow-write --allow-run --allow-env  https://deno.land/x/denoflow/cli.ts

然后就可以使用 denoflow run , 或者 denoflow run <files>来运行你的工作流文件。

Update to latest version

更新到最新版本:

deno cache --reload https://deno.land/x/denoflow/cli.ts

Usage

命令行参数:

denoflow/0.0.17

Usage:
  $ denoflow run [...files or url]

Options:
  --force Force run workflow files, if true, will ignore to read/save state
  --debug Debug mode, will print more info
  --database Database uri, default json://data
  --limit max items for workflow every runs
  --sleep sleep time between sources, filter, steps, unit seconds
  --stdin read yaml file from stdin, e.g. cat test.yml | denoflow run --stdin
  -h, --help Display this message

YAML Syntax

YAML语法:

如果你还不熟悉YAML语法的话,可以花5分钟熟悉一下:

你可以在任何字段中使用${{variable}}来向你的工作流插入变量,我们在所有可以使用脚本的地方都注入了ctx全局变量,利用ctx去访问任何需要的数据,比如说:

Expressions

steps:
  - if: ${{ctx.items.lengh>10}}
    run: console.log(ctx.item);

所有的ctx变量,可以参考接口配置文件

状态

你可以简单地使用ctx.state来获取或设置状态,例如。

let currentState = ctx.state || {};

let sent = ctx.state.send || [];

if(sent.includes(ctx.item.id)){
  sent.push(ctx.item.id)。
}

ctx.state = {
  sent
};

// denoflow将为你保存状态,接下来你可以读取它

默认配置,state将以json格式保存到data文件夹。你也可以使用sqlite来存储数据。在工作流配置文件中设置database: sqlite://data.sqlite即可

Faq

如何运行一个定时工作流?

因为denoflow是为无服务器设计的,很简单,所以它本身不能运行定时工作流。但是你可以使用cron或其他触发器来触发Denoflow的工作流。比如说使用cron:

*/15 * * * deno run --allow-read --allow-net --allow-write --allow-env --allow-run https://deno.land/x/denoflow/cli.ts run workflows/schedule15.yml

如何处理webhook事件?

像上面一样,denoflow不能直接处理webhook,你可以把webhook转发给denoflow,比如使用github actions的例子。

Webhook.yml:

sources:
  - run: return [ctx.env.event]
    force: true
steps: 
  - run: console.log("item",ctx.item);

.github/workflows/webhook.yml:

name: Webhook
on:
  repository_dispatch:
  workflow_dispatch:
jobs:
  denoflow:
    runs-on: ubuntu-latest
    concurrency: denoflow
    steps:
      - name: Check out repository code
        uses: actions/checkout@v2
      - uses: denoland/setup-deno@v1
        with:
          deno-version: v1.x
      - env:
          event: ${{toJSON(github.event)}}
        run: deno run --allow-read --allow-net --allow-write --allow-env --allow-run https://deno.land/x/denoflow/cli.ts run workflows/webhook.yml

Denoflow还处于早期的阶段,如果你有任何建议,非常欢迎issue和pull request。谢谢!