Github Action Bot

1.前言

DevNow 是一个精简的开源技术博客项目模版,支持 Vercel 一键部署,支持评论、搜索等功能,欢迎大家体验。

目前我自己的 Blog 项目也是基于 DevNow 来部署在 Vercel 上的,看到很多项目都基于 TG Bot 来进行一些消息通知和维护,就想着自己也维护一个 DevNow 开源项目频道,看到一些好的前端技术文章也会同步进来,也希望可以给大家提供一个交流的平台。

2.如何把消息通知到 Telegram

2.1 创建Tg Bot

首先要去 BotFather 里 创建一个 Bot,然后获取到 Bot 的 Token,然后把 Bot 添加到你想要通知的 频道 或者 APP 中,我合理选择的是APP,我作为官方的来推送一些内容,然后大家可以在 Chat 频道 进行交流,这样就不会出现消息太多,不方便查看的情况。

2.2 获取 chat_id

当我们将 bot 添加到对应的 APP 或者 频道中,发送一个对话后,我们可以通过以下命令来获取对应的 chat_id

sh 复制代码
curl https://api.telegram.org/bot<token>/getUpdates

结果大概类似:

json 复制代码
{
  "ok": true,
  "result": [
    {
      "update_id": 123456789,
      "message": {
        "message_id": 123,
        "from": {
          "id": -123456789,
          "is_bot": true,
          "first_name": "My Bot",
          "username": "my_bot"
        },
        "chat": {
          "id": -123456789,
          "type": "private",
          "title": "My Chat",
          "username": "my_chat"
        },
        "date": 123456789,
        "text": "Hello, world!"
      }
    }
  ]
}

记录下对应的 chat_idbot Token ,我们在后续的部署过程中会使用到。

3 部署相关的通知服务

3.1 通过 Github WebHook 部署

js 复制代码
import Koa from 'koa';
import Router from 'koa-router';
import bodyParser from 'koa-bodyparser';
import TelegramBot from 'node-telegram-bot-api';
import { Context } from 'koa';
import config from './config';

// Configuration
const token = config.token;
const TELEGRAM_CHAT_ID = process.env.TELEGRAM_CHAT_ID || config.chat_id; // Add your chat ID here

// Initialize Koa and Router
const app = new Koa();
const router = new Router();

// Initialize Telegram bot
// 这里是因为 Vercel 的服务问题,不支持轮训,只支持 Functions,所以用需要改成 webhook 形式
const bot = new TelegramBot(token, {
  webHook: {
    port: 3003
  }
});

// Middleware
app.use(bodyParser());

interface GitHubWebhookPayload {
  commits: {
    added: string[]
  }[]
}

// GitHub webhook endpoint
router.post('/tg/github', async (ctx: Context) => {
  const payload = ctx.request.body as GitHubWebhookPayload;

  try {
    // Handle push events
    if (ctx.headers['x-github-event'] === 'push') {
      const commits = payload.commits || [];
      const newFiles: string[] = [];

      for (const commit of commits) {
        const addedFiles = commit.added || []; // Get added files from the commit
        for (const file of addedFiles) {
          // Check if the file is in the specified directory
          if (file.startsWith('src/content/doc/')) {
            const fileName = file.split('/').pop() as string; // Get the file name
						const url = `https://www.laughingzhu.cn/posts/${fileName}`;
						const telegramMessage = `🔔 New Post: ${url}`;
						await bot.sendMessage(TELEGRAM_CHAT_ID, telegramMessage, {
							parse_mode: 'HTML',
							disable_web_page_preview: false
						});
          }
        }
      }
		}
    ctx.status = 200;
    ctx.body = { success: true };
  } catch (error) {
    console.error('Error processing webhook:', error);
    ctx.status = 500;
    ctx.body = { success: false, error: error instanceof Error ? error.message : 'Unknown error' };
  }
});

// Use router middleware
app.use(router.routes());
app.use(router.allowedMethods());

export default app.callback();

大致的思路就是我在发布新的文章时,会将文件内容推送到 Github 仓库中,然后通过 Github 配置的 WebHook(push) 会将这个事件推送到 webhook 的地址,我们可以进行相应的处理,通过对 commits.added 进行判断新增的文章,这样就可以实现对新文章的推送到 Telegram 上了。

遇到的问题

由于我是通过 Vercel 部署的,所以当 Github push commit 触发 webhook 的时候, Vercel 才开始编译,所以这个时候文章可能还没有生成,如果用的是 SSG 的模式的话,就需要构建这些新的内容,如果是 SSR 的渲染模式,那么还好。这里的问题就是我希望推送可以加载出来 open-graph 这些内容,所有是期望 Vercel 部署成功后再推送。这里就不好整, Github webhook 没有对应的事件,理论上是需要 Vercelwebhook 来通知,但是 VercelWebhook 不知道啥时候变成 Pro 及以上版本的权益了,免费版不支持,所以这个方案就被pass了。

3.2 通过 Github Action 部署 (推荐)

yaml 复制代码
name: Tg Deploy Notification
on: deployment_status

jobs:
  notify:
    runs-on: ubuntu-latest
    if: github.event.deployment_status.state == 'success'
    steps:
      - name: Send Telegram Notification
        env:
          BOT_TOKEN: ${{ secrets.BOT_TOKEN }}
          CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
        run: |
          # 获取最近修改的文件
          FILES=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
            "https://api.github.com/repos/${{ github.repository }}/commits/${{ github.sha }}" \
            | jq -r '.files[].filename')

          # 遍历文件并发送通知
          echo "$FILES" | while read -r file; do
            if [[ $file == src/content/* ]] && [[ $file == *.md* ]]; then
              filename=$(basename "$file")
              name="${filename%.*}"
              URL="https://www.laughingzhu.cn/posts/${name}"
              MESSAGE="🔔 新文章已发布: ${URL}"
              
              curl -s -X POST \
                "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
                -d "chat_id=${CHAT_ID}" \
                -d "text=${MESSAGE}" \
                -d "parse_mode=HTML" \
                -d "disable_web_page_preview=false"
            fi
          done

这样就可以再部署成功后进行推送了,这个方式是最简单的,如果有更好的方案可以大家可以分享下。

写到这里才发现这个部署的 webhook 也是有的,deployment_status,所以理论上也可以在方案一的基础上进行扩展实现。

不过相比在 Vercel 部署一个服务的话, Github Action 还是最简单的,俺也推荐大家使用这种方式。

接下来看效果图:

最后 👏🏻 欢迎大家加入 DevNow 频道 学习交流,摸鱼也可以。

相关推荐
HED15 分钟前
用扣子快速手撸人生中第一个AI智能应用!
前端·人工智能
DN金猿19 分钟前
使用npm install或cnpm install报错解决
前端·npm·node.js
丘山子20 分钟前
一些鲜为人知的 IP 地址怪异写法
前端·后端·tcp/ip
志存高远6632 分钟前
Kotlin 的 suspend 关键字
前端
OpenC++38 分钟前
【C++QT】Buttons 按钮控件详解
c++·经验分享·qt·leetcode·microsoft
www_pp_1 小时前
# 构建词汇表:自然语言处理中的关键步骤
前端·javascript·自然语言处理·easyui
天天扭码1 小时前
总所周知,JavaScript中有很多函数定义方式,如何“因地制宜”?(ˉ﹃ˉ)
前端·javascript·面试
一个专注写代码的程序媛1 小时前
为什么vue的key值,不用index?
前端·javascript·vue.js
장숙혜2 小时前
ElementUi的Dropdown下拉菜单的详细介绍及使用
前端·javascript·vue.js
火柴盒zhang2 小时前
websheet之 编辑器
开发语言·前端·javascript·编辑器·spreadsheet·websheet