使用无服务器自动回复 GitHub 问题

2025-06-08

使用无服务器自动回复 GitHub 问题

您是否曾经在 GitHub 上为开源软件项目做出贡献,例如创建了一个问题,并立即收到了回复?如果回复中包含您的感谢,岂不美哉?本文将介绍一种自动创建节日主题“感谢”回复的方法,该回复将自动发送至您在一个或多个 GitHub 仓库中创建的所有问题。

如果您需要参考,这里是源代码的链接。

图表

本文是#25DaysOfServerless 活动的一部分。整个 12 月,Microsoft Cloud Advocates 每天都会发布新的挑战。了解更多关于 Microsoft Azure 如何实现您的无服务器功能的信息。有想法或解决方案?

想要让这个故事“节日快乐”吗?一个可行的解决方案是使用 Azure Functions 通过 Webhook 监听 GitHub,然后针对该问题创建评论进行响应。我们先来了解一下你需要什么,然后再逐步介绍你可以亲自尝试的步骤。

方法

好的,让我们先回顾一下你接下来要做的事情。当 GitHub 上创建了一个问题时,你需要感谢问题的创建者报告了这个问题。

您需要知道该问题何时创建,因此您需要请求 GitHub 在创建问题时发出警报。GitHub 通过 Webhook 向我们发出警报。该 Webhook 由正在创建的问题触发,然后向您定义的 URL 发出 HTTP 请求,并传递已创建问题的有效负载。那么,GitHub Webhook 的 HTTP 请求会发送到哪里呢?它会调用您使用 Azure Functions 创建的函数。

您将创建一个函数,该函数接受 Webhook 请求并检查其有效负载。您将解析有效负载中的创建者和其他详细信息,并格式化对该问题的响应。现在您已经拥有了创建该问题评论所需的数据,您需要一种方法来回复同一问题并创建评论。然后,您将调用 GitHub API 来创建该问题的评论,并使用允许该函数进行调用的令牌。

您正在 GitHub 存储库和 Azure Functions 之间进行通信,因此您需要确保您拥有在它们之间发出这些 HTTP 请求的正确权限。这非常简单,正如您将在下面的解决方案中看到的那样。

以下是您将要做的事情的摘要:

  • 在我们的一个 GitHub 存储库上创建一个 webhook,当创建问题时触发
  • 创建一个 Azure 函数来接受 Webhook 发出的 HTTP 请求
  • 生成函数在与 GitHub API 通信时可以使用的个人访问令牌
  • 从函数向 GitHub API 发出 HTTP 请求以创建评论

现在您已经计划好了要做的事情,让我们开始将它们整合在一起。

资源和工具🚀

选择合适的工具,可以带来翻天覆地的变化。让我们从使用Visual Studio CodeAzure Functions 扩展开始。在我看来,这种组合是入门并高效创建 Azure Functions 的最佳方式。

如果您没有 Azure 帐户,您可以通过此处的链接注册Azure 免费试用版

安装正确的工具

创建函数

您将首先在 Visual Studio Code 中创建 Azure Function 应用。

创建 Azure 函数项目

  1. 创建新文件夹并命名thank-you
  2. 打开 VS Code 并打开thank-you文件夹
  3. F1键打开命令面板。
  4. 输入并选择Azure Functions:创建新项目
  5. 如果提示在文件夹中创建项目thank-you,请按“是”
  6. 选择TypeScript作为新项目的语言
  7. 选择HTTP Trigger作为函数的模板
  8. 将函数命名为SayThankYou
  9. 选择匿名作为授权级别

VS Code 现在将创建函数项目thank-youSayThankYou f

测试函数

让我们安装项目的依赖项

  1. 按F1打开命令面板
  2. 进入并选择Terminal:Create new integration Terminal
  3. 在终端中输入npm install,安装项目的依赖项
  4. F5运行该函数
  5. 转到浏览器并在地址栏中输入http://localhost:7071/api/saythankyou?name=Colleen

该函数将通过说“Hello Colleen”来响应浏览器

要停止函数应用运行,请执行以下操作:

  1. 按F1打开命令面板
  2. 输入并选择Debug: Disconnect

触发器是一个 webhook

您需要告诉该函数它是由 GitHub webhook 触发的。

  1. 打开function.json文件
  2. 修改 JSON 以", webHookType": "github"在后面添加"methods": ["get", "post"],

有效载荷是多少?

您需要了解函数将从 webhook 接收的有效负载的形状。您可以在GitHub 文档IssuesEvent中找到相应的有效负载形状

当您读取函数中的有效载荷时,您将引用此有效载荷信息。

在继续之前,让我们用以下启动代码替换函数中的代码。

import { AzureFunction, Context, HttpRequest } from '@azure/functions';

const httpTrigger: AzureFunction = async function(context: Context, req: HttpRequest): Promise<void> {
  const { body: payload } = req;

  let body = 'Nothing to see here';

  context.res = { status: 200, body };
};

该函数从请求中收集有效负载,然后始终以相同的主体和状态进行响应。接下来,您将重构该函数以从 Webhook 中读取有效负载。

读取有效载荷

您想创建一条消息来感谢问题创建者。您可能需要收集以下信息:问题创建者的用户名、问题编号、仓库名称、仓库所有者以及触发 Webhook 的操作。

使用IssuesEvent 此处的 GitHub 文档作为参考,您可以编写以下代码从有效负载中收集这些值。

// Gather the data from the payload from the webhook
const repo = payload.repository.name;
const owner = payload.repository.owner.login;
const issue_number = payload.issue.number;
const user = payload.issue.user.login;
const action = payload.action;

现在您的函数将类似于以下代码。

import { AzureFunction, Context, HttpRequest } from '@azure/functions';

const httpTrigger: AzureFunction = async function(context: Context, req: HttpRequest): Promise<void> {
  const { body: payload } = req;

  // Gather the data from the payload from the webhook
  const repo = payload.repository.name;
  const owner = payload.repository.owner.login;
  const issue_number = payload.issue.number;
  const user = payload.issue.user.login;
  const action = payload.action;

  let body = 'Nothing to see here';

  context.res = { status: 200, body };
};

制定回应

现在您可以读取有效负载,您需要编写用于创建问题评论的消息。您只需要在触发 Webhook 的事件创建了问题时撰写评论。创建 Webhook 后,您就会知道它来自问题事件。您不想响应编辑或删除问题的操作,因此我们需要查看action问题事件是否是由打开问题引起的。

以下代码仅在问题被打开(创建)时才会创建消息。

let body = 'Nothing to see here';
if (action === 'opened') {
  body = `Thank you @${user} for creating this issue!\n\nHave a Happy Holiday season!`;
  context.log(body);
}

您的函数现在应该类似于以下代码。

import { AzureFunction, Context, HttpRequest } from '@azure/functions';

const httpTrigger: AzureFunction = async function(context: Context, req: HttpRequest): Promise<void> {
  const { body: payload } = req;

  const repo = payload.repository.name;
  const owner = payload.repository.owner.login;
  const issue_number = payload.issue.number;
  const user = payload.issue.user.login;
  const action = payload.action;

  let body = 'Nothing to see here';
  if (action === 'opened') {
    body = `Thank you @${user} for creating this issue!\n\nHave a Happy Holiday season!`;
    context.log(body);
  }

  context.res = { status: 200, body };
};

生成个人访问令牌

在我们开始编写代码来创建评论之前,我们需要从 GitHub 生成一个个人访问令牌,以便我们可以让我们的函数与 GitHub 对话。

您只希望令牌能够访问公共存储库,因此请确保仅选择public_repo范围。

  1. 请按照以下步骤生成个人访问令牌。仅当系统要求您选择令牌的范围时,才选择public_repo 。
  2. 将令牌复制到剪贴板

令牌是机密信息,不应粘贴到我们的代码中或存储在存储库中。Azure Functions 允许在local.settings.json文件中设置机密信息和环境变量。此文件默认位于.gitignore文件中,因此它仅存在于您的本地计算机上。接下来,您将在此文件中添加令牌的设置。

local.settings.json文件仅适用于在计算机上本地运行该函数的情况。当需要将此函数推送到 Azure 时,您还将了解如何推送这些设置。

  1. 在您的函数项目中打开该local.settings.json文件。
  2. Values名为githubKey
  3. 将令牌粘贴为值

您的local.settings.json代码应该看起来像下面的代码,除了您的令牌。

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "",
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "githubKey": "YOUR_TOKEN_GOES_HERE"
  }
}

在 GitHub 存储库中创建评论

现在您已经拥有了令牌以及想要写入仓库中新评论的消息,接下来需要告诉 GitHub 针对该问题创建一条评论。有几种方法可以做到这一点。一些常见的方法是使用axios之类的 HTTP 库直接向 GitHub API 发出 HTTP 请求,或者使用抽象并简化 HTTP 请求的库。我们选择后者。

Octokit/rest.js是一个 JavaScript 的 GitHub REST API 客户端。它公开了一个 API,可以轻松创建评论。接下来让我们安装@octokit/rest 。

  1. 在项目文件夹中打开终端
  2. 跑步npm install @octokit/rest

您将需要从库中导入Octokit和。IssuesCreateCommentParams

import * as Octokit from '@octokit/rest';
import { IssuesCreateCommentParams } from '@octokit/rest';

通过制作类型的对象来创建评论IssuesCreateCommentParams

const comment: IssuesCreateCommentParams = {
  repo,
  owner,
  issue_number,
  body
};

现在是时候使用库来创建评论了。创建评论的重要 API 是异步函数。但在调用它之前,您需要通过 Octokit 将个人访问令牌从您的函数传递给 GitHub 的 API。您可以通过引用octokit.issues.createComment()从文件中检索令牌local.settings.jsonprocess.env.githubKey

我们可以编写以下函数来获取个人访问令牌,将其传递给 Octokit,并创建评论。

async function createComment(comment: IssuesCreateCommentParams) {
  const auth = process.env.githubKey;
  const octokit = new Octokit({ auth });
  const response = await octokit.issues.createComment(comment);
  return response;
}

现在我们可以在撰写评论后立即调用该函数。

if (payload.action === 'opened') {
  body = `Thank you @${user} for creating this issue!\n\nHave a Happy Holiday season!`;
  const comment: IssuesCreateCommentParams = {
    repo,
    owner,
    issue_number,
    body
  };
  await createComment(comment);
}

你的最终功能

您的功能代码现在应该已经完成​​并且应该类似于下面的代码。

import { AzureFunction, Context, HttpRequest } from '@azure/functions';
import * as Octokit from '@octokit/rest';
import { IssuesCreateCommentParams } from '@octokit/rest';

const httpTrigger: AzureFunction = async function(context: Context, req: HttpRequest): Promise<void> {
  const { body: payload } = req;

  const repo = payload.repository.name;
  const owner = payload.repository.owner.login;
  const issue_number = payload.issue.number;
  const user = payload.issue.user.login;
  const action = payload.action;

  let body = 'Nothing to see here';

  if (action === 'opened') {
    body = `Thank you @${user} for creating this issue!\n\nHave a Happy Holiday season!`;
    const comment: IssuesCreateCommentParams = {
      repo,
      owner,
      issue_number,
      body
    };
    await createComment(comment);
  }

  context.res = { status: 200, body };
};

async function createComment(comment: IssuesCreateCommentParams) {
  const auth = process.env.githubKey;
  const octokit = new Octokit({ auth });
  const response = await octokit.issues.createComment(comment);
  return response;
}

export default httpTrigger;

您的功能现已完成!

将函数推送到 Azure

接下来,您需要将函数推送到 Azure。首先,您需要一个 Azure 帐户。如果您没有,可以在此处创建 Azure 免费试用版

  1. 打开命令面板F1
  2. 输入并选择Azure Functions: 在 Azure 中创建函数应用
  3. 输入全局唯一标识符(名称)
  4. 如果出现提示,请选择操作系统
  5. 选择Node.js 10.x
  6. 选择要创建函数应用的区域

你现在正在 Azure 中创建函数。准备就绪后,VS Code 会提醒你。

在 Azure 中创建应用程序后,您必须将local.settings.json文件中的设置推送到 Azure 中的应用程序。

  1. 打开命令面板F1
  2. 输入并选择Azure Functions:上传本地设置
  3. 出现提示时,选择您的函数应用程序

你刚刚创建了函数并将其推送到 Azure。下一步是为你的一个 GitHub 存储库创建 Webhook。

设置 webhook

您想要为其中一个存储库设置一个 webhook,每次在该存储库中创建问题时都会触发该 webhook。

设置此 webhook 分为两个步骤。第一步是告诉 webhook 哪些事件应该触发它。第二步是告诉 webhook 应该将 HTTP 请求发送到哪个 URL。让我们逐步了解如何设置您的 webhook。

创建 webhook

让我们在您现有的一个存储库中创建 webhook。

  1. 使用您的网络浏览器登录您的GitHub 帐户
  2. 导航到您的一个存储库。
  3. 选择“设置”选项卡。
  4. 从左侧菜单中选择webhook 。
  5. “添加 webhook”按钮为该存储库创建一个新的 webhook
  6. 内容类型设置为applicaiton/json

接下来,你需要函数应用的 URL。该 URL 可以在 VS Code 中找到。

  1. 转到 Azure 函数扩展
  2. 展开函数应用和函数节点
  3. 右键单击您的“SayThankYou”功能
  4. 选择复制函数网址
  5. 返回到您正在设置 webhook 的浏览器
  6. 将您的 URL 粘贴到Payload URL字段中
  7. 选中单个事件复选框
  8. 选中“问题”复选框
  9. 保存 webhook

现在,你的 webhook 已经准备好在问题发生时触发调用。webhook 会将有效负载发送到你的函数,你的函数会读取有效负载,生成一条消息,然后使用 GitHub API 为该问题创建评论!

尝试一下

剩下要做的就是看看它是否有效。你应该前往你的代码库并创建一个 issue。webhook 会触发一个 HTTP 请求,并将一个有效负载传递给你的函数。你的函数会将一条新的评论写回你的 issue,你应该很快就能看到它了。

成功!

显示代码

您可以按照以下步骤从头开始尝试。您也可以直接跳到此处的代码解决方案

如果您遇到困难,请在 repo 中打开一个问题。

下一步

通过免费培训了解有关无服务器的更多信息!

资源

我推荐这些资源,因为它们非常有助于解释所有关键要素。

额外资源⭐️

一般来说,一些额外的很棒的无服务器资源如下。


想要提交你的解决方案来应对这项挑战吗?请在本地构建解决方案,然后提交问题。如果你的解决方案不涉及代码,你可以录制一段简短的视频,并将其作为问题描述中的链接提交。请务必告诉我们该解决方案针对的是哪个挑战。我们期待看到你的成果!你有任何意见或问题吗?请在下方评论区留言。


12月,我们将庆祝无服务器25天,惊喜不断,敬请关注。敬请关注dev.to,我们将带来挑战和解决方案!立即注册Azure免费帐户,准备迎接挑战!

鏂囩珷鏉ユ簮锛�https://dev.to/azure/automate-your-replies-to-github-issues-5280
PREV
构建💣 Bomb-Diggity 技术演示文稿(🎤 Mic Drop 可选)👉🏻 使用 JavaScript 构建演示文稿 TypeScript
NEXT
宣布推出全新免费课程:机器学习入门