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

此版本的 GitHub Enterprise 已停止服务 March 02, 2021. 即使针对重大安全问题,也不会发布补丁。 要获得更好的性能、改进的安全性和新功能,请升级到 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 集成