我们经常发布文档更新,此页面的翻译可能仍在进行中。有关最新信息,请访问英文文档。如果此页面上的翻译有问题,请告诉我们

此版本的 GitHub Enterprise 已停止服务 2020-11-12. 即使针对重大安全问题,也不会发布补丁。 要获得更好的性能、改进的安全性和新功能,请升级到 GitHub Enterprise 的最新版本。 如需升级方面的帮助,请联系 GitHub Enterprise 支持

交付部署

使用部署 REST API,您可以构建与您的服务器和第三方应用程序交互的自定义工具。

本文内容

部署 API 为您托管在 GitHub Enterprise Server 上的项目提供在您自己的服务器上启动它们的功能。 结合 状态 API,您将能够在您的代码到达 master 时协调部署。

本指南将使用该 API 来演示您可以使用的设置。 在我们的场景中,我们将:

  • 合并拉取请求
  • 在 CI 完成后,我们将相应地设置拉取请求的状态。
  • 合并拉取请求后,我们将在服务器上运行部署。

我们的 CI 系统和主机服务器将是我们想象中的虚拟物。 它们可能是 Heroku、Amazon 或其他完全不同的工具。 本指南的重点是设置和配置负责管理通信的服务器。

请务必下载 ngrok(如果尚未下载),并了解如何使用它。 我们发现它在暴露本地连接方面是一款非常有用的工具。

注:您可以从平台样本仓库下载此项目的完整源代码。

编写服务器

我们将编写一个快速的 Sinatra 应用程序,以证明我们的本地连接工作正常。 首先编写以下代码:

require 'sinatra'
require 'json'

post '/event_handler' do
  payload = JSON.parse(params[:payload])
  "Well, it worked!"
end

(如果您不熟悉 Sinatra 的工作方式,建议您阅读 Sinatra 指南)。

启动此服务器。 默认情况下,Sinatra 在端口 4567 上启动,因此您还需要配置 ngrok 开始监听。

为了使此服务器正常工作,我们需要使用 web 挂钩来设置一个仓库。 Web 挂钩应配置为在创建或合并拉取请求时触发。 继续创建一个您可以自由支配的仓库。 我们可以推荐 @octocat 的 Spoon/Knife 仓库吗? 之后,您将在自己的仓库中创建新的 web 挂钩,向其馈送 ngrok 给您的 URL,并选择 application/x-www-form-urlencoded 作为内容类型:

新的 ngrok URL

单击 Update webhook。 您应该会看到正文为 Well, it worked! 的响应。 太好了! 单击 Let me select individual events(让我选择单个事件),然后选择以下项:

  • 部署
  • 部署状态
  • 拉取请求

在发生相关操作时,GitHub Enterprise Server 会将这些事件发送到我们的服务器。 我们将服务器配置为在合并拉取请求时立即处理:

post '/event_handler' do
  @payload = JSON.parse(params[:payload])

  case request.env['HTTP_X_GITHUB_EVENT']
  when "pull_request"
    if @payload["action"] == "closed" && @payload["pull_request"]["merged"]
      puts "A pull request was merged! A deployment should start now..."
    end
  end
end

发生了什么? GitHub Enterprise Server 发送的每个事件都附有 X-GitHub-Event HTTP 标头。 我们现在只关注拉取请求事件。 当拉取请求被合并时(其状态为 closed,并且 mergedtrue),我们将启动部署。

要测试此概念验证,请在测试仓库的分支中进行一些更改,打开拉取请求,然后合并它。 您的服务器应该会做出相应的响应!

处理部署

服务器已就位,代码在接受审查,拉取请求已合并,现在我们需要部署项目。

我们将首先修改事件侦听器,以便在拉取请求被合并时对其进行处理,并开始关注部署:

when "pull_request"
  if @payload["action"] == "closed" && @payload["pull_request"]["merged"]
    start_deployment(@payload["pull_request"])
  end
when "deployment"
  process_deployment(@payload)
when "deployment_status"
  update_deployment_status
end

根据拉取请求中的信息,我们将首先填写 start_deployment 方法:

def start_deployment(pull_request)
  user = pull_request['user']['login']
  payload = JSON.generate(:environment => 'production', :deploy_user => user)
  @client.create_deployment(pull_request['head']['repo']['full_name'], pull_request['head']['sha'], {:payload => payload, :description => "Deploying my sweet branch"})
end

部署可以附加一些元数据,其形式为 payloaddescription。 尽管这些值是可选的,但对于记录和表示信息很有帮助。

创建新部署时,将触发完全独立的事件。 因此我们的事件处理程序中有一个用于 deployment 的新 switch 单元。 在触发部署时,您可以根据此信息得到通知。

部署可能需要很长时间,因此我们需要侦听各种事件,例如,部署创建时间以及部署处于什么状态。

让我们模拟一个能够完成某些工作的部署,并注意它对输出的影响。 首先,我们来完成 process_deployment 方法:

def process_deployment
  payload = JSON.parse(@payload['payload'])
  # you can send this information to your chat room, monitor, pager, etc.
  puts "Processing '#{@payload['description']}' for #{payload['deploy_user']} to #{payload['environment']}"
  sleep 2 # simulate work
  @client.create_deployment_status("repos/#{@payload['repository']['full_name']}/deployments/#{@payload['id']}", 'pending')
  sleep 2 # simulate work
  @client.create_deployment_status("repos/#{@payload['repository']['full_name']}/deployments/#{@payload['id']}", 'success')
end

最后,我们将模拟将状态信息存储为控制台输出:

def update_deployment_status
  puts "Deployment status for #{@payload['id']} is #{@payload['state']}"
end

我们来分析一下发生了什么。 一个新的部署由 start_support 创建,它触发 deployment 事件。 我们从那里调用 process_deployment 来模拟正在进行的工作。 在处理过程中,我们还调用 create_deployment_status,当我们将状态切换到 pending 时,它让接收者知道发生了什么。

部署完成后,我们将状态设置为 success

结论

在 GitHub,我们多年来一直使用 Heaven 版本来管理部署。 基本流程本质上与我们上面构建的服务器完全相同。 在 GitHub,我们:

  • 等待关于 CI 状态的响应
  • 如果代码为绿色,我们将合并拉取请求
  • Heaven 提取合并的代码,并将其部署到我们的生产和暂存服务器上
  • 同时。Heaven 还通过坐在我们聊天室中的 Hubot 通知所有人有关构建的信息

搞定! 使用此示例并不需要构建自己的部署设置。 您始终可以依赖 GitHub 集成