前言
每天看着不断推送的手机消息,明知道其中有价值的并不多,但是又怕错过有价值的信息,这种心态在当今是一种很普遍的心态。因此,面对这种局面,如何摆脱海量信息的冲击和无价值信息的禁锢,是面对的一个艰巨的挑战。之前看到一篇文章——优化自己的信息源,建议主动获取信息。回想我的信息管理方法,差不多也是按照这个思路来的,一般是:
- 收集:初步加上标签和分类;
- 预处理:检视阅读,找出其中要点;
- 深度阅读:阅读,加上摘要和思考内容;
最后这些标注和内容都汇总到我的notion数据库中,但是逐渐发现缺乏回顾的环节,手动去获取这些积累的信息,也存在实际操作性不强的问题,我是如何艰难地克服「效率成瘾」的?建议我们要自动化一些操作来提升效率。
因此,我希望通过自动化的方法来回顾我看过和思考的内容。
方案
整体设计
- Notion API自动化获取信息;
- Github Actions提供workflow;
- 微信接收——Notion打开;
说明
- 信息存储在Notion中,因此使用其提供的API实现自动化的获取;
- 具体的回顾方式:每天定时发送,因此需要事件触发机制——定时周期发送,这种实现方法有很多,本文采用Github Actions,因为免费且可用性很强;
- 接收方式:微信接收最方面,但是其SDK存在一些麻烦,因此一种间接的方式是通过发邮件到QQ邮箱,然后在微信中接收,然后利用默认浏览器打开Notion的链接;
具体过程
Notion API
本文不会介绍Notion。
这里使用Notion API来查询数据库。其中注意使用的是filter和sort。其中需要考虑的问题是:
- 查询API endpoints的方法;
- 在workflow中使用curl:简单、直接,但是不能进行复杂逻辑的操作,比如生成随机数;
- 使用JavaScript查询:这个可以直接用原生js查询,也可以使用Notion提供的SDK。
- API响应结果的解析
- 这个需要进行测试,我感觉Notion给出的API文档说的不够清楚,需要自己去试,可能会出现很多问题;
- 这里我使用postman进行接口的测试;
- 还有一个要吐槽的是:Notion API中好像没有获取整篇文档的接口和选择,只能获取page的url;
Github Actions
1. 触发事件
2. 设计actions
本文设计了两个workflow,其实也不一定这样设计,主要我是为了多了解一下Github Actions的使用,如果你觉得麻烦可以放到一个workflow里,说到这里,想起之前看到的一篇文章——新技术学习不完全指北:以 Rust 为例。其中有一个观点,超纲训练是巩固知识的可靠方式,我这里也算超纲训练一下。
第一个workflow用来获取Notion中的信息,使用Notion提供的JavaScript SDK实现,具体包括:
- 查询Notion database,并根据属性过滤和排序文章列表,以实现随机获取文章;
- 生成文章摘要模板,用于后续的邮件发送;
第二个workflow主要是利用上一个workflow生成的信息并发送邮件,其中需要实现:
- 编排不同的jobs;
- 获取jobs之间共享的信息,并发送出去:这里使用已有的actions完成邮件的发送;
技术细节
重用workflow
由于本文设计了两个workflows,从程序设计的角度看,其实是为了解耦以实现重用已有的workflow。类似于函数的设计,需要遵从一定的规范,比如:为了安全性,有些函数通过加限定符规定只能被同一个模块下的函数调用。Github Actions中也有类似的规定,与其说这些workflow像函数,不如说它们更像RPC。每个workflow都可以包含一个或者多个jobs,也就可以视为一个或者多个进程。
为了重用可共享的workflow,要求:
- 需要复用的workflow支持
workflow_call
出发事件;name: notion-article-query # Controls when the workflow will run on: workflow_call:
这样,此workflow才能在别的workflow中使用,该workflow只能在别的workflow的jobs中使用,而不是steps。并且需要满足一定的条件,即如下其一:
- 两个workflows需要在同一个目录下;
- 被重用的workflow需要存储在共有仓库并且组织允许你使用这些公有仓库;
name: notion-article-review
on:
schedule:
- cron: '0 4 * * *'
workflow_dispatch:
jobs:
article-query:
uses: ./.github/workflows/notion-article-query.yml
secrets: inherit
article-review:
runs-on: ubuntu-latest
更多复杂的功能可以参考Github Actions的文档。
jobs之间共享数据
首先从直觉上来看,不同的jobs可能在不同的虚拟机上,因此通过文件等方式是无法完成数据是共享的,这与RPC也是类似的。照着这个思路来想:
- 引入第三方
- 使用缓存服务器:如Redis,在Github Actions可以使用Cache,官方提供了可以直接使用的Cache Action;
- 使用文件上传和下载:在Github Actions中使用Artifacts实现;
Caching is used to re-use data/files between jobs or workflows while Artifacts are used to save files after workflow ended.
- workflow执行返回
- 使用命令行:定义jobs的输出可以使用命令行的方式,官方直接给出例子,其中的命令是Github Actions专有的命令,可以参考文档 Workflow commands for GitHub Actions,告诉你怎么完成output的设置;
这一点本文没有使用。echo "::workflow-command parameter1={data},parameter2={data}::{command value}"
- 使用JavaScript:这种适合复杂逻辑的场景,本文使用这种方式,通过引入
@actions/core
完成输入和输出的设置,本文利用这个实现文章摘要的传递。
注意,这是一个step中实现的输出,为了在重用的workflow中输出数据,需要将steps中的输出映射到jobs中,如下:const core = require("@actions/core") let context = ` <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> </head> <body> <p>题目:${title}</p> <p>标签:${tags}</p> <p>总结:${summary}</p> <p>链接:<a href="${url}">文章内容</a></p> </body> </html> `; core.setOutput('article-item', context)
在其他的workflow中使用时,如下:on: workflow_call: outputs: article-item: description: "article items" value: ${{ jobs.query-article.outputs.output1 }} jobs: query-article: outputs: output1: ${{ steps.query-step.outputs.article-item }} steps: - name: Query Notion Articles id: query-step # 对应上述index.js的执行和输出 run: npm install && npm run server
其中jobs: article-query: uses: ./.github/workflows/notion-article-query.yml secrets: inherit article-review: needs: article-query steps: - name: send mail uses: dawidd6/action-send-mail@master with: html_body: ${{ needs.article-query.outputs.article-item }}
needs
是用于编排不同的jobs的,后续会说明,直接引用这里使用的workflow并获取对应的输出的参数即可。
- 使用命令行:定义jobs的输出可以使用命令行的方式,官方直接给出例子,其中的命令是Github Actions专有的命令,可以参考文档 Workflow commands for GitHub Actions,告诉你怎么完成output的设置;
编排jobs
如果没有加限制,不同的jobs之间是独立的,例如上述的两个workflow作为两个jobs使用时,如果不加限制,article-review可能无法获取article-query的article-item结果,因为它可能先执行结束,因此需要 needs
来保证不同的jobs的执行顺序,从而构建一个dependency graph,使得不同的jobs之间可以串行、并行等。
本文需要保证 article-review 在article-query之后执行,因此需要needs
来维护依赖关系。
注意secrets
存储secrets
敏感的信息保证不存在在代码中,Github提供一种不公开的方式,同时还定义了不同的粒度,可以参考具体文档。
使用secrets
这些secrets可以作为环境变量在workflow中使用,这里需要使用Github Actions提供的 secrets
context实现,具体参考文档,代码如下:
name: Query Notion Articles
id: query-step
run: npm install && npm run server
env:
# Required mail server address:
NOTION_API_KEY: ${{ secrets.NOTION_API_KEY }}
# Required mail server port:
DATABASE_ID: ${{ secrets.ARTICLE_DATABASE_ID }}
不同workflow之间传递secrets
这个问题可能很少有人提到,我在构建的时候遇到这个问题,在重用已有的workflow时,如果也存在secrets需要保密,需要在调用workflow中声明引用的workflow将集成本workflow下的所有secrets,操作如下:
jobs:
article-query:
uses: ./.github/workflows/notion-article-query.yml
secrets: inherit
article-review:
runs-on: ubuntu-latest
具体细节可以参考文档。
邮件模板
本文只是设计了一个简单文章摘要,包括:
- 题目
- 标签
- 总结
- 文章内容的url;
一种锦上添花的操作是使用HTML Email,阮一峰专门针对这个写了一篇文章,可以参考。
总结
整个项目的代码在仓库,最终的结果如下:
总的来看,这个过程:
- 熟悉了Notion API和Github Actions的操作;
- 打开了Github Actions的有趣的世界,有很多的项目可以借鉴:
- Actionsflow,也可以替代Github Actions实现workflow。
- 自动同步博客文章到Github,这个后边准备加入到我的仓库中;
- 整理Newsletter;
- 更大的收获,应该是让自己看过的和思考的内容不再堆在某个充满尘土的角落里,让知识和思想流动起来!