您可以使用 REST API 将提交与测试服务关联起来,这样您每次推送都可以进行测试并在 GitHub 拉取请求中呈现。有关相关端点的更多信息,请参阅提交状态的 REST API 端点。
本指南将使用该 API 演示一种可供使用的设置。在我们的场景中,我们将
- 在打开拉取请求时运行我们的 CI 套件(我们会将 CI 状态设为 pending)。
- CI 完成后,我们将相应地设置拉取请求的状态。
我们的 CI 系统和托管服务器将是我们想象中的产物。它们可以是 Travis、Jenkins,或完全其他的东西。本指南的核心在于设置和配置管理通信的服务器。
如果您尚未下载,请下载 ngrok,并学习如何使用它。我们发现它是将本地应用暴露到互联网的非常有用的工具。
注意
或者,您也可以使用 webhook 转发来设置本地环境接收 webhook。更多信息,请参阅使用 GitHub CLI 转发 webhook 进行测试。
注意:您可以从platform-samples 仓库下载此项目的完整源代码。
编写服务器
我们将编写一个简短的 Sinatra 应用,以验证本地连接是否正常。让我们从这个开始
require 'sinatra'
require 'json'
post '/event_handler' do
payload = JSON.parse(params[:payload])
"Well, it worked!"
end
(如果您不熟悉 Sinatra 的工作方式,建议阅读 Sinatra 指南。)
启动此服务器。默认情况下,Sinatra 运行在 4567 端口,因此您也需要配置 ngrok 监听该端口。
为了使服务器工作,我们需要为仓库设置 webhook。该 webhook 应配置为在拉取请求被创建或合并时触发。
请创建一个您可以随意实验的仓库。我们建议使用@octocat 的 Spoon/Knife 仓库。
之后,您需要在仓库中创建一个新的 webhook,填入 ngrok 提供的 URL,并选择 application/x-www-form-urlencoded 作为内容类型。
点击Update webhook。您应该会看到响应体Well, it worked!。太好了!点击Let me select individual events,并选择如下内容
- 状态
- 拉取请求
这些是 GitHub 在相应操作发生时发送到我们服务器的事件。现在让我们更新服务器,仅处理拉取请求的情形。
post '/event_handler' do
@payload = JSON.parse(params[:payload])
case request.env['HTTP_X_GITHUB_EVENT']
when "pull_request"
if @payload["action"] == "opened"
process_pull_request(@payload["pull_request"])
end
end
end
helpers do
def process_pull_request(pull_request)
puts "It's #{pull_request['title']}"
end
end
发生了什么?GitHub 发送的每个事件都会附带一个X-GitHub-Event HTTP 头。我们暂时只关注 PR 事件。随后,我们会获取负载信息,并返回 title 字段。理想情况下,服务器应在每次拉取请求更新时都处理,而不仅仅是在打开时,以确保每次新的推送都通过 CI 测试。但在本演示中,我们只处理打开时的情况。
要测试此概念验证,请在测试仓库的分支中进行一些更改并打开拉取请求。服务器应相应地作出响应!
处理状态
有了服务器后,我们即可开始第一个需求,即设置(和更新)CI 状态。请注意,每当您更新服务器时,都可以点击Redeliver重新发送相同的负载。无需每次更改后都创建新的拉取请求!
由于我们要与 GitHub API 交互,将使用Octokit.rb来管理交互。我们将使用个人访问令牌配置该客户端。
# !!! DO NOT EVER USE HARD-CODED VALUES IN A REAL APP !!!
# Instead, set and test environment variables, like below
ACCESS_TOKEN = ENV['MY_PERSONAL_TOKEN']
before do
@client ||= Octokit::Client.new(:access_token => ACCESS_TOKEN)
end
之后,我们只需在 GitHub 上更新拉取请求,以表明我们正在进行 CI 处理。
def process_pull_request(pull_request)
puts "Processing pull request..."
@client.create_status(pull_request['base']['repo']['full_name'], pull_request['head']['sha'], 'pending')
end
我们这里做了三件非常基础的事
- 查询仓库的完整名称
- 查询拉取请求的最新 SHA
- 将状态设置为 "pending"
就是这样!接下来,您可以运行任何需要的流程来执行测试套件。例如,将代码交给 Jenkins,或通过其 API 调用其他 Web 服务,如 Travis。之后,请务必再次更新状态。在我们的示例中,我们将其设为 "success"
def process_pull_request(pull_request)
@client.create_status(pull_request['base']['repo']['full_name'], pull_request['head']['sha'], 'pending')
sleep 2 # do busy work...
@client.create_status(pull_request['base']['repo']['full_name'], pull_request['head']['sha'], 'success')
puts "Pull request processed!"
end
结论
在 GitHub,我们多年使用 Janky 的一个版本来管理 CI。基本流程与我们上面构建的服务器本质上相同。在 GitHub,我们
- 在拉取请求创建或更新时触发 Jenkins(通过 Janky)
- 等待 CI 状态的响应
- 如果代码通过测试(绿色),我们合并拉取请求
所有这些通信都会回流到我们的聊天频道。您无需自行构建 CI 环境即可使用本示例。您始终可以依赖GitHub 集成。