使用 Node.js 创建拉取请求状态服务器
Azure DevOps Services |Azure DevOps Server 2022 - Azure DevOps Server 2019
拉取请求(PR)工作流为开发人员提供了从同行和自动化工具获取代码反馈的机会。 非 Microsoft 工具和服务可以使用 PR 状态 API参与 PR 工作流。 本文指导你完成创建状态服务器以验证 Azure DevOps Services Git 存储库中的 PR 的过程。 有关 PR 状态的详细信息,请参阅 使用拉取请求状态自定义和扩展拉取请求工作流。
先决条件
- 使用 Git 存储库的 Azure DevOps 中的组织。 如果没有组织,注册 来上传和共享代码到免费无限制的私有 Git 存储库中。
- 安装 VS Code 或其他所选代码编辑器。 本指南中的说明使用 VS Code,但其他代码编辑器中的步骤类似。
安装 Node.js
若要安装 Node.js,下载适用于平台的 LTS 版本。 下载包含一个安装程序,可在本地计算机上安装 Node.js 运行时。 安装 Node.js时,请务必保留安装 npm 包管理器 部分,该部分默认处于选中状态。
使用 Express 创建基本 Web 服务器
本节中的步骤使用 Express,它是一种轻型 Web 框架,用于 Node.js,提供许多简化创建 Web 服务器的 HTTP 实用工具方法。 此框架提供侦听 PR 事件所需的基本函数。
在命令行中,为 Web 服务器创建新的项目文件夹。
mkdir pr-server cd pr-server
使用
npm init
命令为项目创建新的package.json
文件。npm init
选择 ,按 Enter 接受除入口点外的所有选项的默认设置。 将其更改为
app.js
entry point: (index.js) app.js
使用以下命令在
pr-server
目录中安装 Express。 这会安装 Express 并将其保存到依赖项列表中。npm install express
为 PR 状态服务器创建一个 Express 应用以作为基础。 以下步骤基于 Express Hello world 示例。 通过从
pr-server
文件夹中运行以下命令,在 VS Code 中打开项目文件夹。code .
创建新文件
(Ctrl + N)
并粘贴以下示例代码。const express = require('express') const app = express() app.get('/', function (req, res) { res.send('Hello World!') }) app.listen(3000, function () { console.log('Example app listening on port 3000!') })
将文件另存为
app.js
。使用以下命令运行基本 Web 服务器:
node app.js
通过浏览到
http://localhost:3000/
来验证服务器是否正在运行。
侦听 HTTP POST 请求
Web 服务器将从 Azure DevOps Services 接收 POST
请求,因此需要在服务器中处理这些请求。
在
app.js
文件的末尾,添加以下代码并保存该文件。app.post('/', function (req, res) { res.send('Received the POST') })
使用以下命令重新运行 Web 服务器:
node app.js
为 PR 事件配置服务挂钩
服务挂钩是一项 Azure DevOps Services 功能,可在发生某些事件时向外部服务发出警报。 对于此示例,为 PR 事件设置两个服务挂钩,以便可以通知状态服务器。 第一个用于 拉取请求创建事件,第二个用于 拉取请求更新事件。
若要接收服务挂钩通知,请向公共 Internet 公开端口。 ngrok 实用工具可用于在开发环境中执行此作。
下载并解压缩适用于平台的相应 ngrok 版本。
使用 ngrok 开始侦听与示例服务器相同的端口 - 端口 3000。 在新命令窗口中运行以下命令。
ngrok http 3000
ngrok 将创建一个转发到
localhost:3000
的公共 URL。 记下 URL,因为下一步需要它。 如以下示例所示:http://c3c1bffa.ngrok.io
转到 Azure DevOps 中的项目,例如
https://dev.azure.com/<your account>/<your project name>
在导航菜单中,将鼠标悬停在 齿轮 上,然后选择 服务挂钩。
如果这是第一个服务挂钩,请选择“+ 创建订阅”。
如果您已配置其他服务钩子,请选择加号“
(+)
”来创建新的服务钩子订阅。在“新建服务挂钩订阅”对话框中,从服务列表中选择“Web 挂钩”,然后选择“下一步”。
从事件触发器列表中选择“已创建拉取请求”,然后选择“下一步”。
在“操作页”中,将 ngrok 的 URL 输入到 URL 框中。 选择 测试 来将测试事件发送到您的服务器。
在 ngrok 控制台窗口中,有一个传入的
POST
,它返回了200 OK
,指示服务器收到了服务挂钩事件。HTTP Requests ------------- POST / 200 OK
在“测试通知”窗口中,选择“响应”选项卡以查看来自服务器的响应的详细信息。 应看到的内容长度为 17,该长度与 POST 处理程序中的字符串长度匹配(例如,“接收 POST”)。
关闭“测试通知”窗口,然后选择“完成”以创建服务挂钩。
再次完成步骤 3-9,但这次是配置“已更新拉取请求”事件。
重要
请务必执行上述步骤两次,为“已创建拉取请求”事件和“已更新拉取请求”事件创建服务挂钩。
将状态发布到 PR
现在,服务器可以在创建新 PR 时接收服务挂钩事件,请将其更新,以便将状态回发 PR。
服务挂钩请求包括描述事件的 JSON 有效负载。 为了帮助分析服务挂钩返回的 JSON,请安装 正文分析器 包。
npm install body-parser
更新
app.js
以使用 body-parser 分析application/json
。var bodyParser = require('body-parser') app.use(bodyParser.json())
若要简化对 Azure Repos 的 REST API 调用,请安装 azure-devops-node-api 包。
npm install azure-devops-node-api
更新
app.js
以使用 azure-devops-node-api 包,设置与帐户的连接详细信息,并获取 Git API 的实例。const vsts = require("azure-devops-node-api") const collectionURL = process.env.COLLECTIONURL const token = process.env.TOKEN var authHandler = vsts.getPersonalAccessTokenHandler(token) var connection = new vsts.WebApi(collectionURL, authHandler) var vstsGit = connection.getGitApi().then( vstsGit => { vstsGit.createPullRequestStatus(prStatus, repoId, pullRequestId).then( result => { console.log(result); }, error => { console.log(error); }) }, error => { console.log(error); } );
为集合 URL 创建环境变量,并将
<your account>
替换为 Azure DevOps 组织的名称。setx COLLECTIONURL "https://dev.azure.com/<your account>"
按照以下说明为应用创建个人身份验证令牌(PAT):使用个人访问令牌进行身份验证。 应为用于访问帐户的每个服务创建新的 PAT,并相应地对其进行命名。
为 PAT 创建环境变量。
setx TOKEN "yourtokengoeshere"
更新
post()
函数,从服务挂钩有效负载中读取 PR 详细信息。 需要这些值才能回发状态。var repoId = req.body.resource.repository.id var pullRequestId = req.body.resource.pullRequestId var title = req.body.resource.title
生成要在 PR 上发布的状态对象。
State
是一种 GitStatusState类型的枚举。 使用succeeded
指示 PR 通过了状态检查并准备好合并。description
是一个字符串值,该值在 PR 详细信息视图中的“状态”部分和活动源向用户显示。targetUrl
是一个 URL,用于在“状态”部分和活动源中创建描述文本的链接,用户可以通过这里获取有关状态的更多信息,例如生成报告或测试执行。 如果未指定 URL,说明将显示为没有链接的文本。上下文
name
和genre
用于对状态进行分类,并将其与其他服务发布状态区分开来。var prStatus = { "state": "succeeded", "description": "Ready for review", "targetUrl": "https://visualstudio.microsoft.com", "context": { "name": "wip-checker", "genre": "continuous-integration" } }
在发布
succeeded
状态之前,检查 PR 标题以查看用户是否通过在标题中添加 WIP 来指示 PR 是否正在进行中。 如果是,请更改回发 PR 的状态。if (title.includes("WIP")) { prStatus.state = "pending" prStatus.description = "Work in progress" }
最后,使用
createPullRequestStatus()
方法发布状态。 它需要状态对象、存储库 ID 和拉取请求 ID。 将响应输出到Node.js控制台,以便查看发布请求的结果。vstsGit.createPullRequestStatus(prStatus, repoId, pullRequestId).then( result => { console.log(result) })
生成的方法应如下所示:
app.post("/", function (req, res) { // Get the details about the PR from the service hook payload var repoId = req.body.resource.repository.id var pullRequestId = req.body.resource.pullRequestId var title = req.body.resource.title // Build the status object that we want to post. // Assume that the PR is ready for review... var prStatus = { "state": "succeeded", "description": "Ready for review", "targetUrl": "https://visualstudio.microsoft.com", "context": { "name": "wip-checker", "genre": "continuous-integration" } } // Check the title to see if there is "WIP" in the title. if (title.includes("WIP")) { // If so, change the status to pending and change the description. prStatus.state = "pending" prStatus.description = "Work in progress" } // Post the status to the PR vstsGit.createPullRequestStatus(prStatus, repoId, pullRequestId).then( result => { console.log(result) }) res.send("Received the POST") })
保存
app.js
并重启节点应用。node app.js
创建新的 PR 以测试状态服务器
现在服务器正在运行并侦听服务挂钩通知,请创建一个拉取请求来测试它。
在文件视图中启动。 编辑存储库中的 readme.md 文件(如果没有 readme.md,则编辑任何其他文件)。
进行编辑并将更改提交到存储库。
请务必将更改提交到新分支,以便在下一步中创建 PR。
选择“创建拉取请求”链接。
在标题中添加 WIP 以测试应用的功能。 选择 创建 以创建 PR。
创建 PR 后,状态部分会显示正在处理条目,该条目链接到有效负载中指定的 URL。
更新 PR 标题并删除 WIP 文本,注意状态将从“正在进行”更改为“可供评审”。