GitHub:https://github.com/wibus-wee/github-event-discord-listener (欢迎 Star 🌟!)

事情的起因

截屏2022-11-02 07.29.16

是这样的,我和 @荆棘 大佬创建了一个新的 Discord 服务器,另外一个大佬说了一个有点意思的东西:同步用户活动,在翻找 GitHub 无果后,我只好自己手写了

想法原理

GitHub 原本是有一个 Webhook 功能的,可以在特定的事件发生时,向指定的 URL 发送一个 HTTP 请求。但是我们需要监听用户活动,第一:我们不可能要每一个用户去配置一个 Webhook,这很明显不可行,并且有可能 private 仓库的活动也会被传播,第二:用户活动的更新反馈是无法被 GitHub 主动触发的。

结合上面的问题,我只好暂时使用 cronjob 来定时向 GitHub 发送请求,获取用户活动, 获取活动有个 API:https://api.github.com/users/${username}/events/public 拿他就完事儿了!

为了实践万物皆可 js的理论,加上我很懒的问题,就使用 node v18 的 fetch 特性来做请求好了。

Coding 部分

正好,GitHub Action 支持 schedule 字段,我们把它设置为 15min 好了

name: "Event Checker"
on:
  push:
    branches:
      - main
  schedule:
    - cron: "*/15 * * * *"    # every 15 minutes
  workflow_dispatch:

如果你并不希望 push 的时候被触发,那就删掉这个字段就好了。

如何发出最新的活动?

我目前的想法是利用文件储存最新的活动id,根据微略的计算,我发现新的 Event ID 都恒大于旧的 Event ID,那我只需要保存最新的 Event ID 比对即可

但不是什么都要广播的,我们只决定广播 Issues, PR, Star (Watch) 活动

那么这个所谓的 “最新”的 Event ID 也应该只是这三个活动当中的最新活动ID,而不是全部的最新活动 ID


为了不想装 node_modules 我全部选择原生的库(fs, fetch),这样就可以很容易被调用了。

const jsonFile = require('./latest.id.json');
const subscribersFile = require('./subscribers.json');

先导入两个文件,一个是最新ID的保存,另一个是订阅用户的username储存,他们大致像是这样的:

// latest.id.json
{"jsun969":"24954043300","wibus-wee":"24969877605",}

// subscribers.json
[ "wibus-wee", "jsun969", ]

这样导入的就是一个 Object,我们也不需要使用 JSON.parse() 等方法了

为了方便发送信息,我们直接定一个产生出 body 的方法

const body = (content, username) => {
  return {
    content,
    username: `[GitHub] ${username}` || "GitHub",
    avatar_url: username ? `https://github.com/${username}.png` : "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png",
  }
}

不但是 content,还使用了 GitHub User 上传的头像,这样发出来或许会更形象一点呼呼呼

由于写得匆忙,我也来不及想那个好那个不行了,我直接就用 forEach 获取一下每一个 username 之后立即发送讯息,并且保存好最新的ID(如果有的话)

usernames.forEach(async function (username) {
  // ...
})

但需要注意的是,我们前面讲了不是什么都要广播的,“最新”的 Event ID 也应该只是这三个活动当中的最新活动ID,而不是全部的最新活动 ID,我选择继续跑这个数组,利用 switch-case 判断 type,如果他是 IssuesEvent, PullRequestEvent, WatchEvent 中的任意一种,就将这次活动的id存入进去,以及把内容 return 出来,如果不是,就return个空的值。

代码中,我对某些变量定义使用了 var,实际上我并不建议使用 var,这是一个将近被弃用的关键词了,我们只有在特殊情况才会用到它,至于这个地方... 可能算吧

最后 filter 方法将空的内容过滤一下就好了,接着用 fs.writeFile 写下文件就 ok 👌 了. 不过最好用 sort 排序一下,取最大的值存入进去(最新的)

欢迎来到 GitHub 给我 Star 一个!